Skip to content

Conversation

@dugshub
Copy link
Contributor

@dugshub dugshub commented Oct 1, 2025

Summary

Complete implementation of type system and security hardening for CLI Patterns.

Commits by Issue

CLI-4: Core Type System

  • ✅ feat(core): add semantic types for wizard system (CLI-4)
  • ✅ feat(core): add runtime-checkable protocols (CLI-4, CLI-5)
  • ✅ feat(core): export complete type system (CLI-4, CLI-5)

CLI-5: Pydantic Models

  • ✅ feat(core): add Pydantic models for wizard configuration (CLI-5)
  • ✅ feat(core): add runtime-checkable protocols (CLI-4, CLI-5)
  • ✅ feat(core): export complete type system (CLI-4, CLI-5)

CLI-6: Security Hardening

  • ✅ feat(core): add validators for DoS protection (CLI-6 Priority 2)
  • ✅ feat(core): add comprehensive security hardening (CLI-6 P2 & P3)
  • ✅ feat(security): add command injection prevention (CLI-6 Priority 1)
  • ✅ feat(core): add production validation (CLI-6 P4)

Security Enhancements

Priority 1 (CRITICAL) - Command Injection:

  • SubprocessExecutor uses create_subprocess_exec() by default
  • allow_shell_features parameter for explicit opt-in
  • 28 security tests

Priority 2 (MEDIUM) - DoS Protection:

  • Depth validation (max 50 levels)
  • Size validation (max 1000 items)
  • 27 validator tests + 30 model tests

Priority 3 (MEDIUM) - Collection Limits:

  • BranchConfig: 100 actions, 50 options, 20 menus
  • WizardConfig: 100 branches
  • SessionState: 1000 options/variables

Priority 4 (LOW) - Production Mode:

  • Environment variable configuration
  • Optional validation mode

Test Results

✅ 782 tests passing
✅ MyPy strict mode clean

Closes CLI-4, CLI-5, CLI-6

�� Generated with Claude Code

dugshub and others added 8 commits September 30, 2025 23:38
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>
@dugshub
Copy link
Contributor Author

dugshub commented Oct 1, 2025

@claude please review this PR

@claude
Copy link

claude bot commented Oct 1, 2025

Claude finished @dugshub's task —— View job


PR Review: Type System & Security Hardening

Review Checklist:

  • Read and analyze core type system changes (types.py)
  • Review Pydantic models (models.py)
  • Review protocols implementation (protocols.py)
  • Review security validators (validators.py)
  • Review security config (config.py)
  • Review subprocess executor security (subprocess_executor.py)
  • Review test coverage and quality
  • Analyze security implementations (command injection, DoS, limits)
  • Check for bugs, type safety issues, and best practices
  • Provide comprehensive feedback

Summary

This 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)


🌟 Strengths

1. Exceptional Security Implementation

  • Command Injection Prevention: Multi-layered defense with validation in BashActionConfig and safe execution in SubprocessExecutor
  • DoS Protection: Robust depth (50 levels) and size (1000 items) validators prevent resource exhaustion
  • Defense in Depth: Security checks at both configuration validation and runtime execution
  • Explicit Opt-in: allow_shell_features flag requires conscious decision for dangerous operations

2. Type Safety Excellence

  • Semantic Types: Proper use of NewType prevents type confusion (e.g., BranchId vs ActionId)
  • Factory Functions: Centralized validation with configurable strictness
  • Type Guards: Runtime type checking with TypeGuard for safe narrowing
  • MyPy Strict Compliance: Clean type hints throughout

3. Excellent Architecture

  • Protocol-Based Design: Clean separation of concerns with runtime-checkable protocols
  • Discriminated Unions: Proper use of Pydantic discriminators for extensibility
  • Configuration Management: Environment-based security config with caching
  • Validation Strategy: Pydantic validators at the right places (field-level and model-level)

4. Outstanding Test Coverage

  • 782 tests passing: Comprehensive coverage across unit and integration tests
  • Security Testing: Dedicated test files for command injection, DoS, and validators
  • Integration Tests: Real subprocess execution tests validate security measures
  • Clear Test Structure: Well-organized with descriptive test names

🔍 Issues Found

Critical Issues

None - No critical issues found.

High Priority Issues

None - No high priority issues found.

Medium Priority Issues

1. 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 counted

Impact: 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 {"a": {}} is depth 1 (one level of nesting).

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 validators module is not exported from core/__init__.py.

Current state:

# core/__init__.py exports types, models, protocols
# But NOT validators module

Impact: Users cannot import validators directly from cli_patterns.core:

# This doesn't work:
from cli_patterns.core import validate_state_value

# Must use:
from cli_patterns.core.validators import validate_state_value

Recommendation: Add validators to the exports:

from cli_patterns.core.validators import (
    ValidationError,
    validate_state_value,
    validate_json_depth,
    validate_collection_size,
)

Low Priority Issues

3. Inconsistent Error Types (models.py:96-127, test_command_injection.py:18-24)

The BashActionConfig.validate_command_safety() validator raises ValueError, but tests expect both ValueError and ValidationError (from Pydantic).

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 ValueError in ValidationError during validation, so both work. However, it's inconsistent.

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 logger.info() for expected usage with appropriate message.


💡 Suggestions for Enhancement

1. 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 self

2. Consider Command Timeout Limits

Add 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:

  • When shell features are enabled
  • When validation is disabled
  • When commands are executed

4. Documentation Enhancement

The code is well-documented, but consider adding:

  • Security best practices guide in docs
  • Migration guide for users upgrading
  • Examples of secure vs. insecure patterns

📊 Code Quality Metrics

Metric Score Notes
Type Safety ⭐⭐⭐⭐⭐ MyPy strict mode, excellent type annotations
Security ⭐⭐⭐⭐⭐ Comprehensive defense-in-depth approach
Test Coverage ⭐⭐⭐⭐⭐ 782 tests, excellent coverage
Documentation ⭐⭐⭐⭐⭐ Clear docstrings and comments
Architecture ⭐⭐⭐⭐⭐ Clean protocols and separation of concerns
Code Style ⭐⭐⭐⭐⭐ Consistent, readable, well-organized

🎯 Specific File Reviews

types.py (src/cli_patterns/core/types.py)

Rating: Excellent ⭐⭐⭐⭐⭐

  • Clean semantic types with factory functions
  • Type guards properly implemented
  • Good separation of concerns
  • Minor: Consider exporting validators in init.py

models.py (src/cli_patterns/core/models.py)

Rating: Excellent ⭐⭐⭐⭐⭐

  • Excellent use of Pydantic discriminated unions
  • Security validators in the right places
  • Good collection size limits
  • Command injection validation is robust

protocols.py (src/cli_patterns/core/protocols.py)

Rating: Excellent ⭐⭐⭐⭐⭐

  • Clean protocol definitions
  • Good docstrings with examples
  • Runtime-checkable for flexibility
  • Good extension point comments

validators.py (src/cli_patterns/core/validators.py)

Rating: Excellent ⭐⭐⭐⭐⭐

  • Well-implemented DoS protection
  • Clear error messages
  • Configurable limits
  • Minor: Clarify depth counting semantics

config.py (src/cli_patterns/core/config.py)

Rating: Excellent ⭐⭐⭐⭐⭐

  • Clean configuration management
  • Good use of TypedDict
  • Environment variable support
  • Caching for performance

subprocess_executor.py (src/cli_patterns/execution/subprocess_executor.py)

Rating: Excellent ⭐⭐⭐⭐⭐

  • Excellent security implementation
  • Safe by default (no shell)
  • Good error handling
  • Proper async implementation
  • Minor: Consider log level configuration

✅ Verification

  • ✅ All tests passing (782 tests)
  • ✅ MyPy strict mode clean
  • ✅ CI passing
  • ✅ Security measures comprehensive
  • ✅ Type system complete
  • ✅ Documentation thorough

🎉 Conclusion

This PR represents excellent engineering work and is ready to merge. The implementation successfully addresses all three issues with production-quality code:

  • CLI-4 (Type System): ✅ Complete semantic types with factory functions and type guards
  • CLI-5 (Pydantic Models): ✅ Comprehensive models with discriminated unions and validation
  • CLI-6 (Security): ✅ Multi-layered security with command injection prevention and DoS protection

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! 🚀


Job RunBranch: CLI-4-5-6-core-type-system

@dugshub dugshub merged commit caa72ee into main Oct 1, 2025
9 checks passed
@dugshub dugshub deleted the CLI-4-5-6-core-type-system branch October 1, 2025 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants