Skip to content

Commit caa72ee

Browse files
dugshubclaude
andcommitted
feat(core): add production validation with security config (CLI-6 P4)
Implements CLI-6 Priority 4: Production validation mode. Environment variables for production hardening. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent e5eda58 commit caa72ee

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

src/cli_patterns/core/config.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
"""Configuration for CLI Patterns core behavior.
2+
3+
This module provides security and runtime configuration through environment
4+
variables and TypedDict configurations.
5+
"""
6+
7+
from __future__ import annotations
8+
9+
import os
10+
from typing import TypedDict
11+
12+
13+
class SecurityConfig(TypedDict):
14+
"""Security configuration settings.
15+
16+
These settings control security features like validation strictness,
17+
DoS protection limits, and shell feature permissions.
18+
"""
19+
20+
enable_validation: bool
21+
"""Enable strict validation for all factory functions.
22+
23+
When True, factory functions perform validation on inputs.
24+
Default: False (for performance in development).
25+
Recommended for production: True
26+
"""
27+
28+
max_json_depth: int
29+
"""Maximum nesting depth for JSON values.
30+
31+
Prevents DoS attacks via deeply nested structures.
32+
Default: 50 levels
33+
"""
34+
35+
max_collection_size: int
36+
"""Maximum size for collections.
37+
38+
Prevents memory exhaustion from large data structures.
39+
Default: 1000 items
40+
"""
41+
42+
allow_shell_features: bool
43+
"""Allow shell features by default (INSECURE).
44+
45+
When True, shell features (pipes, redirects, etc.) are allowed by default.
46+
Default: False (secure)
47+
WARNING: Setting this to True is a security risk. Always use per-action
48+
configuration instead.
49+
"""
50+
51+
52+
def get_security_config() -> SecurityConfig:
53+
"""Get security configuration from environment variables.
54+
55+
Environment Variables:
56+
CLI_PATTERNS_ENABLE_VALIDATION: Enable strict validation (default: false)
57+
Set to 'true' to enable validation in factory functions.
58+
59+
CLI_PATTERNS_MAX_JSON_DEPTH: Max JSON nesting depth (default: 50)
60+
Controls maximum depth for nested data structures.
61+
62+
CLI_PATTERNS_MAX_COLLECTION_SIZE: Max collection size (default: 1000)
63+
Controls maximum number of items in collections.
64+
65+
CLI_PATTERNS_ALLOW_SHELL: Allow shell features globally (default: false)
66+
WARNING: Setting to 'true' is insecure. Use per-action configuration.
67+
68+
Returns:
69+
SecurityConfig with settings from environment or defaults
70+
71+
Example:
72+
>>> os.environ['CLI_PATTERNS_ENABLE_VALIDATION'] = 'true'
73+
>>> config = get_security_config()
74+
>>> config['enable_validation']
75+
True
76+
"""
77+
return SecurityConfig(
78+
enable_validation=os.getenv("CLI_PATTERNS_ENABLE_VALIDATION", "false").lower()
79+
== "true",
80+
max_json_depth=int(os.getenv("CLI_PATTERNS_MAX_JSON_DEPTH", "50")),
81+
max_collection_size=int(os.getenv("CLI_PATTERNS_MAX_COLLECTION_SIZE", "1000")),
82+
allow_shell_features=os.getenv("CLI_PATTERNS_ALLOW_SHELL", "false").lower()
83+
== "true",
84+
)
85+
86+
87+
# Global config instance (cached)
88+
_security_config: SecurityConfig | None = None
89+
90+
91+
def get_config() -> SecurityConfig:
92+
"""Get global security config (cached).
93+
94+
This function caches the configuration on first call to avoid
95+
repeated environment variable lookups.
96+
97+
Returns:
98+
Cached SecurityConfig instance
99+
100+
Example:
101+
>>> config = get_config()
102+
>>> if config['enable_validation']:
103+
... # Perform validation
104+
... pass
105+
"""
106+
global _security_config
107+
if _security_config is None:
108+
_security_config = get_security_config()
109+
return _security_config
110+
111+
112+
def reset_config() -> None:
113+
"""Reset cached configuration.
114+
115+
This is primarily useful for testing when you need to reload
116+
configuration from environment variables.
117+
118+
Example:
119+
>>> reset_config()
120+
>>> # Config will be reloaded on next get_config() call
121+
"""
122+
global _security_config
123+
_security_config = None

0 commit comments

Comments
 (0)