-
Notifications
You must be signed in to change notification settings - Fork 0
Complete type system with comprehensive security hardening (CLI-4, CLI-5, CLI-6) #23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Implements CLI-4: Core type system foundation with semantic types. Types Added: - BranchId: Semantic type for branch identifiers - ActionId: Semantic type for action identifiers - OptionKey: Semantic type for option keys - MenuId: Semantic type for menu identifiers - StateValue: JSON-serializable values for state storage Factory Functions: - make_branch_id(), make_action_id(), make_option_key(), make_menu_id() - Optional validation parameter (validate: bool = False) - Zero-overhead by default, opt-in validation for development Type Guards: - is_branch_id(), is_action_id(), is_option_key(), is_menu_id() - Runtime type checking with TypeGuard support Benefits: - Type safety: Prevents ID type confusion at compile time - MyPy strict mode compliance - Zero runtime overhead (NewType pattern) - Clear semantic meaning in function signatures Tests: 28 unit tests covering all factory functions and type guards 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Implements CLI-5: Complete Pydantic model structure for wizard system. Models Added: Action Types (Discriminated Union): - BashActionConfig: Bash command execution with env variables - PythonActionConfig: Python function invocation - ActionConfigUnion: Type-safe discriminated union Option Types (Discriminated Union): - StringOptionConfig: Text input - SelectOptionConfig: Dropdown/menu selection - PathOptionConfig: File/directory path input - NumberOptionConfig: Numeric input with min/max - BooleanOptionConfig: Yes/no toggle - OptionConfigUnion: Type-safe discriminated union Navigation & Structure: - MenuConfig: Navigation menu items - BranchConfig: Wizard screen/step with actions, options, menus - WizardConfig: Complete wizard with entry point and branches State Management: - SessionState: Unified state for wizard and parser - Current branch tracking - Navigation history - Option values - Variables for interpolation - Parser state (mode, command history) Result Types: - ActionResult: Action execution results - CollectionResult: Option collection results - NavigationResult: Navigation operation results Features: - StrictModel base class with Pydantic v2 strict mode - Field validation with descriptive error messages - JSON serialization/deserialization support - Metadata and tagging infrastructure - MyPy strict mode compliance Tests: 159 unit tests covering all models and validation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
… CLI-5) Implements extensibility layer for CLI-4 and CLI-5 with runtime-checkable protocols. Protocols Added: Core Wizard Protocols: - WizardConfig: Complete wizard definition (title, branches, entry point) - BranchConfig: Branch/screen definition (actions, options, menus) - SessionState: Runtime state management (navigation, options, variables) Execution Protocols: - ActionExecutor: Execute actions with state context - execute_action(action_id, state) -> ActionResult - Supports async execution - OptionCollector: Collect user input for options - collect_option(option_key, state) -> CollectionResult - Interactive input handling - NavigationController: Handle branch navigation - navigate(target, state) -> NavigationResult - History management Features: - All protocols are @runtime_checkable for isinstance() checks - Protocol-oriented design enables flexible implementations - Clear contracts for extensibility points - MyPy strict mode compliance - Async support where appropriate Benefits: - Loose coupling between components - Easy to mock for testing - Multiple implementations possible - Type-safe extension points Tests: 15 unit tests verifying protocol compliance 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Implements public API for CLI-4 and CLI-5 type system. Exports Added: From types.py: - Core semantic types: BranchId, ActionId, OptionKey, MenuId, StateValue - Factory functions: make_branch_id, make_action_id, make_option_key, make_menu_id - Type guards: is_branch_id, is_action_id, is_option_key, is_menu_id - Collection types: BranchList, BranchSet, ActionList, ActionSet, OptionDict, MenuList From models.py: - Base: StrictModel, BaseConfig - Actions: BashActionConfig, PythonActionConfig, ActionConfigUnion - Options: StringOptionConfig, SelectOptionConfig, PathOptionConfig, NumberOptionConfig, BooleanOptionConfig, OptionConfigUnion - Navigation: MenuConfig, BranchConfig, WizardConfig - State: SessionState, StateValue - Results: ActionResult, CollectionResult, NavigationResult From protocols.py: - Core protocols: WizardConfig, BranchConfig, SessionState - Execution protocols: ActionExecutor, OptionCollector, NavigationController Benefits: - Clean public API surface - Single import point: from cli_patterns.core import ... - Clear separation of public vs internal APIs - Complete type system available to consumers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Implements CLI-6 Priority 2 (MEDIUM): DoS protection via depth and size validation. Validators Added: 1. validate_json_depth(value, max_depth=50) - Prevents stack overflow from deeply nested structures - Recursively checks dict/list nesting depth - Default limit: 50 levels - Raises ValidationError if exceeded 2. validate_collection_size(value, max_size=1000) - Prevents memory exhaustion from large collections - Counts all items recursively (nested dicts/lists) - Default limit: 1000 total items - Raises ValidationError if exceeded 3. validate_state_value(value) - Combined depth + size validation - Primary validator for StateValue types - Ensures JSON-serializable data is safe Configuration Constants: - MAX_JSON_DEPTH = 50 (configurable) - MAX_COLLECTION_SIZE = 1000 (configurable) Security Benefits: - Prevents DoS attacks via deeply nested JSON - Prevents memory exhaustion from large data structures - Protects against malicious configuration files - Safe limits for production environments Integration: - Used by SessionState validators (next commit) - Applied to option_values and variables fields - Configurable via environment variables (future) Tests: 27 unit tests covering all validators and edge cases 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…ority 2 & 3)
Implements CLI-6 Priority 2 & 3: DoS protection integrated into Pydantic models.
Security Enhancements:
1. BashActionConfig:
- allow_shell_features field (default: False)
- Command validation rejecting dangerous patterns:
* Command chaining (;, &, |)
* Command substitution ($(), backticks)
* Redirection (<, >)
* Variable expansion (${})
* Variable assignment
- Security documentation in docstrings
- Explicit opt-in required for shell features
2. Collection Size Limits (CLI-6 Priority 3):
- BranchConfig: max 100 actions, 50 options, 20 menus
- WizardConfig: max 100 branches
- SessionState: max 1000 option_values, 1000 variables
- Field validators enforce limits at model instantiation
3. SessionState Validators (CLI-6 Priority 2):
- option_values validated with validate_state_value()
- variables validated with validate_state_value()
- Enforces depth limit (50 levels)
- Enforces size limit (1000 items)
- Prevents DoS via nested/large data structures
4. WizardConfig Validation:
- Validates entry_branch exists in branches list
- Provides helpful error messages with available branches
Security Impact:
- Command injection blocked at model validation
- DoS attacks via deep nesting prevented
- DoS attacks via large collections prevented
- Memory exhaustion risks eliminated
Tests: 30 security-specific tests (test_security.py)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
…r (CLI-6 Priority 1)
Implements CLI-6 Priority 1 (CRITICAL): Command injection prevention.
Changes to SubprocessExecutor:
- Uses create_subprocess_exec() by default (safe mode)
- Added allow_shell_features parameter (default: False)
- Commands parsed with shlex.split() for safe execution
- Security warning logged when shell features enabled
- Invalid shell syntax caught and reported gracefully
- Empty command detection with clear error messages
Security Model:
- Default: Shell disabled, commands executed directly
- Opt-in: allow_shell_features=True enables shell interpretation
- Shell metacharacters treated as literals in safe mode
- Prevents all command injection attack vectors
Breaking Change:
Commands now execute without shell by default. Migration:
# Before (VULNERABLE)
await executor.run("echo test | grep foo")
# After (safe - literal pipe character)
await executor.run("echo test | grep foo") # | is literal
# Or opt-in to shell features (trusted commands only)
await executor.run("echo test | grep foo", allow_shell_features=True)
Tests Added:
- 15 command injection unit tests (test_command_injection.py)
- 13 security integration tests (test_subprocess_security.py)
- Updated 8 existing subprocess executor tests
Test Coverage:
- Command chaining blocked (;, &, &&)
- Pipe operations blocked (|)
- Command substitution blocked ($(), backticks)
- Redirection blocked (<, >)
- Quoted arguments handled safely
- Invalid syntax handled gracefully
All 782 tests passing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
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>
|
@claude please review this PR |
|
Claude finished @dugshub's task —— View job PR Review: Type System & Security HardeningReview Checklist:
SummaryThis is an excellent, production-ready implementation that successfully delivers on all three issues (CLI-4, CLI-5, CLI-6). The code demonstrates strong engineering principles with comprehensive security hardening, excellent type safety, and thorough test coverage. The implementation is clean, well-documented, and follows best practices. Recommendation: ✅ APPROVE (with minor suggestions below) 🌟 Strengths1. Exceptional Security Implementation
2. Type Safety Excellence
3. Excellent Architecture
4. Outstanding Test Coverage
🔍 Issues FoundCritical IssuesNone - No critical issues found. High Priority IssuesNone - No high priority issues found. Medium Priority Issues1. Depth Validation Edge Case (models.py:403-433, validators.py:41-82)The depth counting implementation has an edge case issue: # In validators.py lines 69-76
if isinstance(obj, dict):
if not obj: # Empty dict is depth 0
return current_depth
return max(check_depth(v, current_depth + 1) for v in obj.values())Issue: An empty container increments depth when nested but not at the top level. Example: {"a": {}} # This is depth 1, not 2 (correct)
{"a": {"b": {}}} # This is depth 2, not 3 (correct)
# BUT the logic suggests inconsistency in how depth is countedImpact: Low - The implementation is actually correct but the comment "Empty dict is depth 0" is misleading. An empty dict at the root is depth 0, but Recommendation: Clarify the comment or add tests that explicitly verify the depth counting semantics with empty containers. 2. Missing Validators Export (core/init.py:1-117)The Current state: # core/__init__.py exports types, models, protocols
# But NOT validators moduleImpact: Users cannot import validators directly from # This doesn't work:
from cli_patterns.core import validate_state_value
# Must use:
from cli_patterns.core.validators import validate_state_valueRecommendation: Add validators to the exports: from cli_patterns.core.validators import (
ValidationError,
validate_state_value,
validate_json_depth,
validate_collection_size,
)Low Priority Issues3. Inconsistent Error Types (models.py:96-127, test_command_injection.py:18-24)The Code: # models.py:121-125
raise ValueError(
f"Command contains {description}. "
f"Set allow_shell_features=True to enable shell features "
f"(SECURITY RISK: only do this for trusted commands)."
)Tests: # test_command_injection.py:18
with pytest.raises(ValueError, match="command chaining"):
# test_security.py:29 (appears to use ValidationError)
with pytest.raises(ValidationError, match="command chaining"):Impact: Very low - Pydantic wraps Recommendation: Either document this behavior or standardize on one approach. 4. Type Annotation Inconsistency (types.py:25-26)Forward reference in type alias could be simplified: # Current (line 26):
JsonValue = Union[JsonPrimitive, list["JsonValue"], dict[str, "JsonValue"]]
# Could use __future__.annotations and remove quotes:
from __future__ import annotations # Already imported!
JsonValue = Union[JsonPrimitive, list[JsonValue], dict[str, JsonValue]]Impact: Negligible - Both work correctly. The current approach is actually fine for recursive type aliases. Recommendation: Keep as-is or update for consistency. Either is acceptable. 5. Logger Warning Usage (subprocess_executor.py:151-153)Logger warning is used when shell features are enabled, but there's no configuration to control log level: logger.warning(
f"Executing command with shell features enabled: {command_str}"
)Impact: Low - Warning logs in production might be excessive if shell features are used intentionally. Recommendation: Consider making this log level configurable or change to 💡 Suggestions for Enhancement1. Add Command Allowlist Pattern (Future Enhancement)For production use, consider adding an allowlist pattern: class BashActionConfig(BaseConfig):
allowed_commands: Optional[list[str]] = None
@model_validator(mode="after")
def validate_command_allowlist(self) -> BashActionConfig:
if self.allowed_commands is not None:
cmd = self.command.split()[0]
if cmd not in self.allowed_commands:
raise ValueError(f"Command '{cmd}' not in allowlist")
return self2. Consider Command Timeout LimitsAdd configurable limits for command execution timeouts to prevent resource exhaustion. 3. Add Security Audit Logging (Future Enhancement)Consider adding audit logging for security-sensitive operations:
4. Documentation EnhancementThe code is well-documented, but consider adding:
📊 Code Quality Metrics
🎯 Specific File Reviewstypes.py (src/cli_patterns/core/types.py)Rating: Excellent ⭐⭐⭐⭐⭐
models.py (src/cli_patterns/core/models.py)Rating: Excellent ⭐⭐⭐⭐⭐
protocols.py (src/cli_patterns/core/protocols.py)Rating: Excellent ⭐⭐⭐⭐⭐
validators.py (src/cli_patterns/core/validators.py)Rating: Excellent ⭐⭐⭐⭐⭐
config.py (src/cli_patterns/core/config.py)Rating: Excellent ⭐⭐⭐⭐⭐
subprocess_executor.py (src/cli_patterns/execution/subprocess_executor.py)Rating: Excellent ⭐⭐⭐⭐⭐
✅ Verification
🎉 ConclusionThis PR represents excellent engineering work and is ready to merge. The implementation successfully addresses all three issues with production-quality code:
The minor issues noted above are suggestions for future enhancements and do not block merging. The code is secure, type-safe, well-tested, and production-ready. Great work! 🚀 |
Summary
Complete implementation of type system and security hardening for CLI Patterns.
Commits by Issue
CLI-4: Core Type System
CLI-5: Pydantic Models
CLI-6: Security Hardening
Security Enhancements
Priority 1 (CRITICAL) - Command Injection: ✅
create_subprocess_exec()by defaultallow_shell_featuresparameter for explicit opt-inPriority 2 (MEDIUM) - DoS Protection: ✅
Priority 3 (MEDIUM) - Collection Limits: ✅
Priority 4 (LOW) - Production Mode: ✅
Test Results
✅ 782 tests passing
✅ MyPy strict mode clean
Closes CLI-4, CLI-5, CLI-6
�� Generated with Claude Code