Coverage for src/taipanstack/security/types.py: 100%
36 statements
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-06 15:01 +0000
« prev ^ index » next coverage.py v7.14.3, created at 2026-07-06 15:01 +0000
1"""
2Pydantic-compatible security types.
4Provide ``Annotated`` type aliases that integrate TaipanStack's
5runtime security guards with Pydantic v2 validation, enabling
6declarative, type-safe input validation inside ``BaseModel``
7definitions.
8"""
10import re
11from typing import Annotated
13from pydantic.functional_validators import AfterValidator
15from taipanstack.core.result import Ok
16from taipanstack.security.guards import (
17 SecurityError,
18 guard_command_injection,
19 guard_path_traversal,
20 guard_ssrf,
21)
22from taipanstack.security.validators import (
23 validate_project_name,
24 validate_url,
25)
28def _validate_safe_url(url: str) -> str:
29 """Validate a URL is safe from SSRF attacks.
31 Args:
32 url: The URL string to validate.
34 Returns:
35 The validated URL.
37 Raises:
38 ValueError: If the URL fails SSRF validation.
40 """
41 result = guard_ssrf(url)
42 if isinstance(result, Ok):
43 return result.ok_value
44 raise ValueError(str(result.err_value)) from result.err_value
47def _validate_safe_path(path: str) -> str:
48 """Validate a path is safe from traversal attacks.
50 Args:
51 path: The path string to validate.
53 Returns:
54 The validated path string.
56 Raises:
57 ValueError: If path traversal is detected.
59 """
60 try:
61 guard_path_traversal(path)
62 except SecurityError as exc:
63 raise ValueError(str(exc)) from exc
64 return path
67def _validate_safe_command(command: str) -> str:
68 """Validate a command string is safe from injection attacks.
70 Args:
71 command: The command string to validate.
73 Returns:
74 The validated command string.
76 Raises:
77 ValueError: If command injection is detected.
79 """
80 try:
81 guard_command_injection([command])
82 except SecurityError as exc:
83 raise ValueError(str(exc)) from exc
84 return command
87def _validate_safe_project_name(name: str) -> str:
88 """Validate a project name conforms to safe naming rules.
90 Args:
91 name: The project name to validate.
93 Returns:
94 The validated project name.
96 Raises:
97 ValueError: If the name is invalid.
99 """
100 return validate_project_name(name)
103def _validate_safe_url_format(url: str) -> str:
104 """Validate a URL has a correct format and allowed scheme.
106 Args:
107 url: The URL string to validate.
109 Returns:
110 The validated URL.
112 Raises:
113 ValueError: If the URL format is invalid.
115 """
116 return validate_url(url)
119SafeUrl = Annotated[
120 str,
121 AfterValidator(_validate_safe_url_format),
122 AfterValidator(_validate_safe_url),
123]
124"""A URL validated for correct format and safe from SSRF attacks."""
126SafePath = Annotated[str, AfterValidator(_validate_safe_path)]
127"""A filesystem path validated against path-traversal attacks."""
129SafeCommand = Annotated[str, AfterValidator(_validate_safe_command)]
130"""A command string validated against shell-injection attacks."""
132SafeProjectName = Annotated[str, AfterValidator(_validate_safe_project_name)]
133"""A project name validated for safe naming conventions."""
136_SQL_IDENTIFIER_REGEX = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*\Z")