omnibase_infra 0.2.9__py3-none-any.whl → 0.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,41 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Database Runtime Models Module.
4
+
5
+ This module exports Pydantic models for database runtime configuration.
6
+ Contract models (ModelDbRepositoryContract, ModelDbOperation, ModelDbReturn)
7
+ are imported from omnibase_core.models.contracts.
8
+
9
+ Exports:
10
+ ModelRepositoryRuntimeConfig: Configuration for PostgresRepositoryRuntime
11
+ - Safety constraints (max_row_limit, timeout_ms)
12
+ - Operation allowlisting (select, insert, update, upsert)
13
+ - Feature flags (allow_raw_operations, allow_delete_operations)
14
+ - Determinism controls (primary_key_column, default_order_by)
15
+ - Metrics emission configuration
16
+
17
+ ModelDbRepositoryContract: (re-export from omnibase_core)
18
+ ModelDbOperation: (re-export from omnibase_core)
19
+ ModelDbReturn: (re-export from omnibase_core)
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ # Contract models from omnibase_core (canonical source)
25
+ from omnibase_core.models.contracts import (
26
+ ModelDbOperation,
27
+ ModelDbRepositoryContract,
28
+ ModelDbReturn,
29
+ )
30
+
31
+ # Runtime config is local to omnibase_infra
32
+ from omnibase_infra.runtime.db.models.model_repository_runtime_config import (
33
+ ModelRepositoryRuntimeConfig,
34
+ )
35
+
36
+ __all__: list[str] = [
37
+ "ModelDbOperation",
38
+ "ModelDbRepositoryContract",
39
+ "ModelDbReturn",
40
+ "ModelRepositoryRuntimeConfig",
41
+ ]
@@ -0,0 +1,211 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Repository Runtime Configuration Model.
4
+
5
+ This module provides the configuration model for PostgresRepositoryRuntime.
6
+ All fields are strongly typed to eliminate Any usage and enable proper validation.
7
+
8
+ Safety Constraints:
9
+ - max_row_limit: Prevents unbounded SELECT queries
10
+ - timeout_ms: Prevents long-running queries from blocking resources
11
+ - allowed_modes: Allowlist of permitted operation modes (read, write)
12
+ - allow_write_operations: Explicit opt-in for write operations
13
+
14
+ Determinism:
15
+ - primary_key_column: Enables ORDER BY injection for stable pagination
16
+ - default_order_by: Default ordering clause when PK is declared
17
+
18
+ Metrics:
19
+ - emit_metrics: Controls whether duration_ms and rows_returned are emitted
20
+
21
+ SQL Identifier Validation:
22
+ - primary_key_column and default_order_by are validated against safe SQL
23
+ identifier patterns to prevent SQL injection from misconfiguration.
24
+ - Pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ for column names
25
+ - ORDER BY allows: column [ASC|DESC] [, column [ASC|DESC]]*
26
+
27
+ Example:
28
+ >>> config = ModelRepositoryRuntimeConfig(
29
+ ... max_row_limit=100,
30
+ ... timeout_ms=5000,
31
+ ... allowed_ops={"select", "insert"},
32
+ ... )
33
+ >>> print(config.allow_raw_operations)
34
+ False
35
+ >>> print("delete" in config.allowed_ops)
36
+ False
37
+ """
38
+
39
+ from __future__ import annotations
40
+
41
+ import re
42
+ from typing import Literal
43
+
44
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
45
+
46
+ # Safe SQL identifier pattern: starts with letter or underscore,
47
+ # followed by letters, digits, or underscores
48
+ _SQL_IDENTIFIER_PATTERN = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$")
49
+
50
+ # ORDER BY clause pattern: column [ASC|DESC]
51
+ # Allows whitespace around components
52
+ _ORDER_BY_COMPONENT_PATTERN = re.compile(
53
+ r"^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*(?:ASC|DESC)?\s*$", re.IGNORECASE
54
+ )
55
+
56
+
57
+ class ModelRepositoryRuntimeConfig(BaseModel):
58
+ """Configuration for PostgresRepositoryRuntime.
59
+
60
+ This model controls safety constraints, allowed operations, determinism
61
+ behavior, and metrics emission for the PostgresRepositoryRuntime.
62
+
63
+ Attributes:
64
+ max_row_limit: Maximum rows for multi-row selects (1-1000, default: 10).
65
+ Prevents unbounded SELECT queries that could return massive result sets.
66
+ timeout_ms: Query timeout in milliseconds (1000-300000, default: 30000).
67
+ Queries exceeding this timeout are cancelled to prevent resource exhaustion.
68
+ allowed_modes: Set of allowed operation modes (read, write).
69
+ Both modes enabled by default. SQL safety is validated by
70
+ omnibase_core validators at contract load time.
71
+ allow_write_operations: Enable 'write' mode operations.
72
+ Default: True. Set to False for read-only configurations.
73
+ primary_key_column: Column name for ORDER BY injection.
74
+ When set, ensures deterministic query results for pagination.
75
+ default_order_by: Default ORDER BY clause when primary_key_column is set.
76
+ Applied when no explicit ORDER BY is provided.
77
+ emit_metrics: Whether to emit duration_ms and rows_returned metrics.
78
+ Enable for observability integration. Default: True.
79
+
80
+ Example:
81
+ >>> from omnibase_infra.runtime.db.models import ModelRepositoryRuntimeConfig
82
+ >>> # Restrictive config for read-only operations
83
+ >>> readonly_config = ModelRepositoryRuntimeConfig(
84
+ ... allowed_modes=frozenset({"read"}),
85
+ ... allow_write_operations=False,
86
+ ... max_row_limit=50,
87
+ ... )
88
+ >>> # Permissive config with higher limits
89
+ >>> admin_config = ModelRepositoryRuntimeConfig(
90
+ ... max_row_limit=500,
91
+ ... )
92
+ """
93
+
94
+ model_config = ConfigDict(
95
+ strict=True,
96
+ frozen=True,
97
+ extra="forbid",
98
+ )
99
+
100
+ # Safety constraints
101
+ max_row_limit: int = Field(
102
+ default=10,
103
+ ge=1,
104
+ le=1000,
105
+ description="Maximum rows for multi-row selects",
106
+ )
107
+ timeout_ms: int = Field(
108
+ default=30000,
109
+ ge=1000,
110
+ le=300000,
111
+ description="Query timeout in milliseconds",
112
+ )
113
+
114
+ # Allowed operation modes (from omnibase_core contract schema)
115
+ # Note: Specific SQL safety is validated by omnibase_core validators at contract load
116
+ allowed_modes: frozenset[Literal["read", "write"]] = Field(
117
+ default=frozenset({"read", "write"}),
118
+ description="Allowed operation modes from contract (read=SELECT, write=INSERT/UPDATE/etc)",
119
+ )
120
+
121
+ # Feature flag for write operations (additional safety layer)
122
+ allow_write_operations: bool = Field(
123
+ default=True,
124
+ description="Enable 'write' mode operations (INSERT, UPDATE, UPSERT)",
125
+ )
126
+
127
+ # Determinism controls
128
+ primary_key_column: str | None = Field(
129
+ default=None,
130
+ description="Primary key column for ORDER BY injection to ensure deterministic results",
131
+ )
132
+ default_order_by: str | None = Field(
133
+ default=None,
134
+ description="Default ORDER BY clause when primary_key_column is declared",
135
+ )
136
+
137
+ # Metrics emission
138
+ emit_metrics: bool = Field(
139
+ default=True,
140
+ description="Emit duration_ms and rows_returned metrics for observability",
141
+ )
142
+
143
+ @field_validator("primary_key_column")
144
+ @classmethod
145
+ def validate_primary_key_column(cls, v: str | None) -> str | None:
146
+ """Validate primary_key_column is a safe SQL identifier.
147
+
148
+ Prevents SQL injection from misconfigured column names.
149
+ Pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$
150
+
151
+ Args:
152
+ v: The column name to validate, or None.
153
+
154
+ Returns:
155
+ The validated column name, or None if not set.
156
+
157
+ Raises:
158
+ ValueError: If the column name contains unsafe characters.
159
+ """
160
+ if v is None:
161
+ return v
162
+ if not _SQL_IDENTIFIER_PATTERN.match(v):
163
+ raise ValueError(
164
+ f"Invalid SQL identifier for primary_key_column: '{v}'. "
165
+ "Must start with a letter or underscore, followed by letters, "
166
+ "digits, or underscores only (pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$)."
167
+ )
168
+ return v
169
+
170
+ @field_validator("default_order_by")
171
+ @classmethod
172
+ def validate_default_order_by(cls, v: str | None) -> str | None:
173
+ """Validate default_order_by contains only safe SQL identifiers.
174
+
175
+ Allows format: column [ASC|DESC] [, column [ASC|DESC]]*
176
+ Prevents SQL injection from misconfigured ORDER BY clauses.
177
+
178
+ Args:
179
+ v: The ORDER BY clause to validate, or None.
180
+
181
+ Returns:
182
+ The validated ORDER BY clause, or None if not set.
183
+
184
+ Raises:
185
+ ValueError: If any column reference contains unsafe characters.
186
+ """
187
+ if v is None:
188
+ return v
189
+
190
+ # Split by comma to get individual column specifications
191
+ components = v.split(",")
192
+
193
+ for component in components:
194
+ component = component.strip()
195
+ if not component:
196
+ raise ValueError(
197
+ f"Invalid ORDER BY clause: '{v}'. "
198
+ "Empty component found after splitting by comma."
199
+ )
200
+ if not _ORDER_BY_COMPONENT_PATTERN.match(component):
201
+ raise ValueError(
202
+ f"Invalid ORDER BY component: '{component}' in '{v}'. "
203
+ "Each component must be a valid SQL identifier optionally "
204
+ "followed by ASC or DESC. Column names must start with a "
205
+ "letter or underscore, followed by letters, digits, or "
206
+ "underscores only."
207
+ )
208
+ return v
209
+
210
+
211
+ __all__: list[str] = ["ModelRepositoryRuntimeConfig"]