CHANGELOG.md•37 kB
# Changelog
All notable changes to mcp-ssh-orchestrator will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.1.0] - 2025-11-21
### Security
- **Command Substitution Bypass Fixed**: Hard-banned all command substitution (`$(...)`, backticks, `$((...))`) to prevent policy bypasses. All command substitution is now blocked before rule evaluation.
- **Path-Based Binaries Blocked**: Path-based binaries (e.g., `/usr/bin/cat`, `./script.sh`) are now always blocked for security. Only binaries in `$PATH` are allowed.
### Added
- **Version 2 Policy Schema**: New argument-aware policy schema with `simple_binaries` and structured rules for precise command control.
- **shlex-Based Argument Parsing**: Commands are now parsed using `shlex` for safe, argument-aware rule matching.
- **Comprehensive Test Coverage**: Added 7 new test files with 100+ tests covering:
- SSH client edge cases and error handling (`test_ssh_coverage.py`, `test_ssh_integration.py`)
- MCP server coverage including notification handlers, context logging, and resource endpoints (`test_mcp_server_coverage.py`, `test_mcp_server_edge_cases.py`, `test_mcp_server_on_tag_coverage.py`)
- Utilities coverage for async task management and progress callbacks (`test_utilities_coverage.py`)
- All tests pass linting (Ruff, Black) and maintain code quality standards
### Changed
- **Breaking: Legacy `commands` Patterns Removed**: Legacy full-line `fnmatch` patterns in `commands` field are no longer supported. All policies must use version 2 schema (`simple_binaries` + structured rules).
- **Breaking: Path-Based Execution**: Path-based binaries are blocked by default. Use structured rules with explicit `binary` name if needed.
- **Code Quality**: All new test files formatted with Black and pass Ruff linting checks. Fixed unused variable warnings and improved code consistency.
### Fixed
- **Command Substitution Bypass**: Fixed 15+ critical bypasses where denied commands could be executed via command substitution (e.g., `echo $(cat /etc/passwd)`).
- **Insecure Full-Line Matching**: Removed insecure full-line `fnmatch` patterns that enabled bypasses.
- **Linting Issues**: Fixed all code linting issues in new test files (blank lines with whitespace, unused imports, unused variables, generator expressions).
## [1.0.0] - 2025-11-19
### Added
- **README Documentation Improvements (#74)**:
- Added interactive mermaid diagram for Defense-in-Depth Architecture visualization
- Enhanced Real-World Use Cases with persona-aligned scenarios (Homelab Enthusiasts, DevOps Teams, Platform Engineers)
- Improved code block formatting throughout the document for better readability
### Changed
- **README Structure (#74)**:
- Fixed all broken code blocks and formatting issues (bash, json, yaml blocks)
- Removed redundant "Docker Build & Inspector Workflow" section (content already in Contributing guide and Usage Cookbook)
- Improved flow and organization for better readability
- Enhanced use case scenarios to be more practical and aligned with target personas
### Fixed
- **Documentation Formatting (#74)**:
- Fixed stray markdown characters and formatting inconsistencies
- Corrected ordered list prefixes to follow markdown linting standards (MD029)
- Removed empty lines in code blocks
- Fixed all markdown linting issues for publication readiness
## [0.9.0] - 2025-11-18
### Added
- **.env File Support for Consolidated Secrets Management (#72)**:
- Added support for consolidated `.env` file in secrets directory for easier secret management
- Maintains backward compatibility with individual secret files
- Implements caching with proper cache invalidation on missing files
- Supports comments, quoted values, and values with `=` characters
- Resolution order: environment variables → `.env` file → individual files
- Added 20 comprehensive tests covering all edge cases
- Updated all documentation with `.env` file usage and examples
### Changed
- **Documentation Comprehensive Review and Alignment (#73)**:
- Fixed markdown linting issues across all documentation files
- Added language tags to fenced code blocks for better syntax highlighting
- Fixed ordered list numbering in SECURITY.md and other wiki documents
- Improved consistency and formatting across docs/wiki files
- Enhanced readability and maintainability of documentation structure
### Security
- **OSSF Scorecard Pinned-Dependencies**: Fixed all 58 Pinned-Dependencies security alerts by pinning all GitHub Actions to commit SHAs and all package managers to specific versions
- Pinned 42 GitHub Actions to commit SHAs (replacing version tags like `@v4`, `@v5`)
- Pinned 1 GitHub Action (`codeql-action/upload-sarif`) to tag `@v4` due to monorepo sub-action verification requirements
- Pinned pip to version 24.0 in all workflows and Dockerfile (5 instances)
- Pinned npm package `markdownlint-cli2` to version 0.19.0
- Improved supply chain security by using immutable commit references instead of mutable version tags
- Expected Scorecard Pinned-Dependencies score improvement: 1/10 → 10/10
- All changes validated with YAML syntax checks, GitHub Actions parsing (act), and consistency verification
- Fixed workflow verification error for `codeql-action/upload-sarif` (imposter commit error)
### Fixed
- **Issue #1**: Fixed SSH client exception handling to be more specific - now only catches `KeyError` and `AttributeError` from host key access, preventing `RuntimeError` from known_hosts check from being incorrectly caught
- **Issue #2**: Fixed DNS cache race condition (TOCTOU) by adding 1-second grace period to expiry check
- **Issue #3**: Fixed cleanup thread to support graceful shutdown via `shutdown()` method and improved exception logging instead of silently ignoring errors
- **Workflow Verification**: Fixed "imposter commit" error in Scorecard workflow by using tag `@v4` for `codeql-action/upload-sarif` (monorepo sub-action requirement)
### Changed
- **Issue #7**: Improved type hints for `_ctx_log()` function - changed `payload: dict | None` to `payload: dict[str, Any] | None` for better type safety
- **Issue #11**: Increased command hash length from 12 to 16 characters (48 to 64 bits) for better collision resistance in audit trails
- **BREAKING**: External tools that parse command hashes may need to update to handle 16-character hashes instead of 12
- **Dependencies**: Updated `sigstore/cosign-installer` from 3.6.0 to 4.0.0
- **Dependencies**: Updated CodeQL SARIF upload action version
### Added
- Comprehensive unit tests for exception handling fixes (3 new tests)
- Unit tests for DNS cache grace period mechanism
- Unit tests for cleanup thread shutdown mechanism
- Unit tests for hash command function (5 new tests in `test_utilities.py`)
- `shutdown()` method to `AsyncTaskManager` for graceful cleanup thread termination
## [0.8.0] - 2025-11-18
### Security
- **CRITICAL FIX**: Fixed command chaining bypass vulnerability where commands like `uptime && apt list --upgradable` could bypass policy restrictions by chaining an allowed command with a denied one
- Command chaining operators (`&&`, `||`, `;`, `|`) are now parsed and each command is validated individually
- All commands in a chain must be allowed for the chain to execute; if any command is denied, the entire chain is blocked
- Enhanced error messages in `ssh_plan` to identify which specific command in a chain is denied
- Added comprehensive security logging for command chain parsing and denials
- Added 25+ unit tests and 8 integration tests for command chaining validation
- Backward compatibility maintained: simple commands (no chaining) work exactly as before
### Added
- Command chain parsing function `_parse_command_chain()` supporting all chaining operators and command substitution
- `get_denied_command_in_chain()` helper method to identify which command in a chain is denied
- Security logging for command chain parsing (`command_chain_parsed`) and denials (`command_chain_denied`)
- Comprehensive documentation for command chaining behavior in policy.yml and troubleshooting guides
- Pre-commit hooks configuration for code quality (Ruff, Black, Mypy, markdownlint, yamllint)
- Validation scripts for MCP schema and YAML configuration files
- Markdown linting fix script for automated documentation formatting
## [0.7.0] - 2025-11-17
### Added
- Enhanced SSH error messages with specific failure reasons (authentication, timeout, connection refused, DNS resolution, etc.)
- Per-host exception handling in `ssh_run_on_tag` - individual host failures no longer stop entire operation
- Comprehensive test coverage for SSH error scenarios (12 new unit tests, 5 new integration tests)
- MCP Inspector automated testing script for error handling validation
- MCP specification compliance tests for error handling patterns
### Changed
- SSH error messages now provide specific, actionable information instead of generic "SSH connection failed"
- `ssh_run_on_tag` now handles per-host failures gracefully, continuing execution on remaining hosts
- Error messages are sanitized for security (no IPs, hostnames, or file paths in user-facing errors)
- Async task error handling now sanitizes error messages before storing/notifying
### Fixed
- Fixed issue where one host failure in `ssh_run_on_tag` would stop execution on all hosts
- Improved error categorization for better troubleshooting (authentication vs network vs configuration errors)
## [0.6.0] - 2025-11-17
### Added
### Changed
### Fixed
## [0.6.0] - 2025-11-17
### Added
- Docker MCP Gateway secret support: secrets can now be injected as direct environment variables (matching `env:` field in `server.yml`) in addition to existing prefixed env vars and file-based secrets
- Support for all 10 Docker MCP Registry secrets (5 passphrase + 5 password) with flexible expansion capability
- Comprehensive test coverage for Docker MCP Gateway secret resolution including unit tests, integration tests, and priority order verification
- Safe MCP resources:
- `ssh://hosts` (inventory), `ssh://host/{alias}`, `ssh://host/{alias}/tags`, `ssh://host/{alias}/capabilities`
- Reuse `_validate_alias()` + `Config` helpers and redact credentials automatically
- Optional context logging for synchronous tooling (`ssh_run`, `ssh_run_on_tag`, `ssh_reload_config`, cancel + async polling) so MCP clients show task start/finish/cancel updates without leaking commands
- Targeted unit tests covering resources + `_ctx_log`, plus Docker helper scripts (`scripts/docker-build.sh`, `scripts/docker-smoketest.sh`) for repeatable inspector validation
- Helper unit tests for policy/network denial responses, plus README/wiki coverage explaining the new hint behavior
### Changed
- Secret resolution priority updated to support Docker MCP Gateway pattern:
1. Direct env var (Docker MCP Gateway): `<SECRET_NAME>` (matches `env:` field in `server.yml`)
2. Prefixed env var (standalone/backward compatibility): `MCP_SSH_SECRET_<SECRET_NAME>`
3. File-based (standalone): `/app/secrets/<secret_name>`
- README, tools reference, observability, and usage cookbook now document the new resources, context logging, and the Docker/Inspector/manual test workflow
- Policy/network denial responses now include MCP-friendly `hint` text (and `ssh_plan` surfaces `why`/`hint` when blocked) so clients know to re-run `ssh_plan`, consult the orchestrator prompts, or explicitly ask about policy/network updates before retrying
### Fixed
## [0.5.0] - 2025-11-15
### Added
- Safe MCP resources:
- `ssh://hosts` (inventory), `ssh://host/{alias}`, `ssh://host/{alias}/tags`, `ssh://host/{alias}/capabilities`
- Reuse `_validate_alias()` + `Config` helpers and redact credentials automatically
- Optional context logging for synchronous tooling (`ssh_run`, `ssh_run_on_tag`, `ssh_reload_config`, cancel + async polling) so MCP clients show task start/finish/cancel updates without leaking commands
- Targeted unit tests covering resources + `_ctx_log`, plus Docker helper scripts (`scripts/docker-build.sh`, `scripts/docker-smoketest.sh`) for repeatable inspector validation
- Helper unit tests for policy/network denial responses, plus README/wiki coverage explaining the new hint behavior
### Changed
- README, tools reference, observability, and usage cookbook now document the new resources, context logging, and the Docker/Inspector/manual test workflow
- Policy/network denial responses now include MCP-friendly `hint` text (and `ssh_plan` surfaces `why`/`hint` when blocked) so clients know to re-run `ssh_plan`, consult the orchestrator prompts, or explicitly ask about policy/network updates before retrying
- Development extras (`pip install ".[dev,test]"`) documented/verified so contributors can run Black/Ruff/Pytest locally just like CI
### Fixed
- Resolved CI lint/test failures by formatting `src/mcp_ssh/mcp_server.py` and the new test suites with Black and ensuring the dev/test extras install pipeline keeps Ruff/Pytest available locally and in automation
## [0.4.0] - 2025-11-13
### Added
- **MCP Prompts Support**: Added 6 prompts to guide LLM behavior
- `ssh_orchestrator_usage` - General usage guidance for SSH orchestrator tools
- `ssh_policy_denied_guidance` - How to handle policy denials
- `ssh_network_denied_guidance` - How to handle network policy denials
- `ssh_missing_host_guidance` - How to handle missing host aliases
- `ssh_missing_credentials_guidance` - How to handle missing/incomplete credentials
- `ssh_config_change_workflow` - Global rules for config change suggestions
- Prompts are exposed via MCP protocol (`prompts/list` and `prompts/get`)
- Prompts help LLMs understand how to safely interact with the orchestrator
- See: [MCP Prompts specification](https://pypi.org/project/mcp/1.21.0/#prompts)
### Changed
- **Structured JSON Denial Responses**: All denial responses now return structured JSON format
- Policy denials return JSON with `status: "denied"`, `reason: "policy"`, `alias`, `hash`, `command`
- Network denials return JSON with `status: "denied"`, `reason: "network"`, `alias`, `hostname`, `detail`
- This improves LLM understanding and enables better prompt-based guidance
- Per MCP recommendation for better structured outputs
- Updated `ssh_run()`, `ssh_run_async()`, and post-connect network denials
### Fixed
## [0.3.8] - 2025-11-13
### Fixed
- **Dockerfile & Dependabot**: Prevented accidental Python 3.14 updates
- Reverted Dockerfile from Python 3.14-slim to Python 3.13-slim (MCP SDK doesn't officially support 3.14 yet)
- Added Dependabot ignore rules to block Python 3.14+ updates in Docker ecosystem
- Fixed Dependabot configuration errors (removed unsupported `reviewers` property, corrected timezone to `America/Detroit`)
- Pinned Python 3.13-slim with SHA256 digest for reproducibility
- Added documentation explaining the Python version constraint
- See: https://github.com/modelcontextprotocol/python-sdk
## [0.3.7] - 2025-11-12
### Changed
- **Dependencies**: Bumped MCP SDK from 1.19.0 to 1.21.0
- Updated to latest MCP SDK version with bug fixes and improvements
- Includes SEP-985: OAuth Protected Resource Metadata discovery fallback
- Added `get_server_capabilities()` to ClientSession
- All tests passing, no breaking changes detected
- See: https://github.com/modelcontextprotocol/python-sdk/releases/tag/v1.21.0
## [0.3.6] - 2025-11-12
### Changed
- **Release Workflow**: Simplified release process by removing problematic Python SBOM generation
- Workflow now relies on GitHub's native dependency graph for Python package SBOM
- Container SBOM generation (Trivy) continues to work reliably
## [0.3.5] - 2025-11-12
### Changed
- **SBOM Generation**: Removed Python package SBOM generation from release workflow
- GitHub's native dependency graph already provides Python package SBOM via UI/API
- Container SBOM (Trivy) remains in releases for OSSF Scorecard compliance
- Simplifies workflow and eliminates cyclonedx-py dependency issues
## [0.3.4] - 2025-11-12
### Added
- **OSSF Scorecard Compliance**: Enhanced release workflow to meet OSSF Scorecard security requirements
- Added Python package SBOM generation (CycloneDX format) for supply chain transparency
- Implemented least-privilege token permissions (read-only at top level, write only at job level)
- Added concurrency control to prevent multiple simultaneous releases
- Added job timeouts to prevent runaway workflows (15min for tests, 45min for release)
- Improved SBOM generation to include only production dependencies
### Changed
- **Release Workflow Security**: Restructured GitHub Actions permissions following principle of least privilege
- Top-level permissions set to read-only for Token-Permissions check compliance
- Write permissions scoped to release job only where needed
- Added comprehensive documentation comments referencing OSSF Scorecard requirements
### Fixed
- **Container Tagging**: Fixed `latest` tag generation in release workflow (removed incorrect branch condition)
- **SBOM Error Handling**: Improved SBOM generation error handling with graceful fallback when Trivy fails
## [0.3.3] - 2025-11-08
### Changed
- **Compose Workflow Polish**: Pinned `docker-compose.yml` to `ghcr.io/samerfarida/mcp-ssh-orchestrator:0.3.3`, refreshed compose documentation, and updated `compose/setup.sh` to generate a baseline `.env` automatically when no template is present.
- **Quick Start Bootstrap**: README now highlights the compose setup script as the fastest path to create config/keys/secrets before running Docker, aligning the hero pitch around declarative policy and zero-trust SSH orchestration.
- **Documentation Cleanup**: Removed references to external compliance frameworks, replaced security tag examples with neutral labels (`critical`, `restricted`, `audit`, `sandbox`), and clarified governance messaging across SECURITY.md and the wiki.
### Removed
- **Legacy Requirements Files**: Dropped `requirements-dev.*` and `requirements-test.*` in favor of installing extras via `pip install -e ".[dev,test]"`, updating the contributor guide accordingly.
### Fixed
- **Unreleased Notification Note**: Carried forward the async notification handler clarification so MCP `ctx.info` calls continue emitting without keyword errors while progress updates still flow via `ctx.report_progress`.
## [0.3.2] - 2025-11-07
### Added
- **MCP Notification Handler Builder**: Added `_build_notification_handler()` so async tasks broadcast lifecycle events through the MCP context APIs while retaining structured logging fallback when no session loop is available.
### Fixed
- **Async Task Notifications**: Reworked async task notifications to use the MCP 2025-06-18 notification pathway—`ssh_run_async` now captures the tool `Context`, schedules updates on the active event loop, and reports progress/info via `ctx.report_progress` / `ctx.info`, eliminating `notification_failed` warnings and restoring real-time updates ([MCP Spec](https://modelcontextprotocol.io/specification/2025-06-18/basic/index#notifications), [Python SDK](https://github.com/modelcontextprotocol/python-sdk/blob/main/README.md)).
- **Security: SSH Host Key Validation (CWE-295)**: Documented the hardening work from commit 46a8919d95ce8e0106bf9bd0c1895ebde4d771d7 that enforces Paramiko's `RejectPolicy()`, ignores unsafe host-key options, and requires known_hosts entries to mitigate MITM risks.
## [0.3.0] - 2025-11-02
### Added
- **Security Audit Logging (PR10)**: Added comprehensive security audit logging for security-relevant events
- Created `_log_security_event()` function with structured JSON format
- Unified all security event logging to use audit format
- Includes both Unix timestamp (ts) and ISO 8601 timestamp (timestamp)
- Logs attempted_path and resolved_path for path-related events
- Logs additional context (field names, sizes, limits, patterns)
- Event types: path_traversal_attempt, file_validation_failed, file_size_limit_exceeded, input_length_limit_exceeded, invalid_secret_name, dns_rate_limit_exceeded, command_bypass_attempt
- Comprehensive tests for audit logging (format validation, path traversal, invalid file access, oversized files, timestamp validation)
- Updated documentation with security audit logging format and event types
- Enables security monitoring and incident response via structured audit trail
- **Input Length Limits for Configuration Parameters (PR9)**: Added length validation for secret names and SSH key paths
- Secret name length limit: 100 characters (prevents oversized secret names in credentials.yml)
- SSH key path length limit: 500 characters (prevents oversized key paths)
- Length validation occurs before other validations (character checks, path traversal checks)
- Security event logging for length limit violations
- Comprehensive tests for length limits (at limit, exceeds limit, under limit)
- Updated documentation with all input length limits (MCP tools + config parameters)
- Complements PR6 input validation for MCP tool parameters (alias, command, tag, task_id)
- **DNS Rate Limiting (PR8)**: Added rate limiting and caching for DNS resolution to prevent DoS attacks
- Rate limiting: Maximum 10 resolutions per second per hostname (time-window based)
- Result caching: 60-second TTL cache for DNS results (reduces DNS server load)
- Timeout protection: 5-second timeout for DNS resolution (prevents hanging)
- Thread-safe implementation for concurrent access
- Rate limit violations logged as security events
- Comprehensive tests for rate limiting, caching, and timeout handling
- Updated documentation with DNS rate limiting details
- **Command Denial Bypass Prevention (PR7)**: Enhanced command denial logic to prevent bypass attempts
- Added `_normalize_command()` function that removes quotes, handles escaped characters, and normalizes whitespace
- Enhanced `is_allowed()` method with dual checking (original + normalized command)
- Added token-based matching for common bypass patterns
- Added security event logging for detected bypass attempts
- Prevents bypasses via: quote obfuscation (`'rm -rf /'`), escaped characters (`rm\ -rf\ /`), whitespace variations
- Comprehensive tests for all bypass prevention techniques
- Updated documentation with bypass prevention details and limitations
- **Input Validation for User-Controlled Parameters (PR6)**: Added comprehensive input validation to prevent injection attacks and resource exhaustion
- Added validation helper functions: `_validate_alias()`, `_validate_command()`, `_validate_tag()`, `_validate_task_id()`
- Alias validation: 100 char limit, alphanumeric/dash/underscore/dot only
- Command validation: 10,000 char limit, rejects null bytes and control characters
- Tag validation: 50 char limit, alphanumeric/dash/underscore/dot only
- Task ID validation: 200 char limit, format validation
- Applied validation to all MCP tools: `ssh_describe_host`, `ssh_plan`, `ssh_run`, `ssh_run_on_tag`, `ssh_run_async`, `ssh_cancel`, `ssh_get_task_status`, `ssh_get_task_result`, `ssh_get_task_output`, `ssh_cancel_async_task`
- Security event logging for injection attempts (null bytes, control characters)
- Comprehensive tests for all validation functions
- Updated documentation with input validation requirements
- **Error Message Sanitization (PR5)**: Added error message sanitization to prevent information disclosure
- All user-facing error messages sanitized to remove sensitive information
- File paths, IP addresses, hostnames, credentials, and port numbers removed from user responses
- Original detailed errors logged to stderr (structured JSON logs) for debugging
- Added `sanitize_error()` function in `mcp_ssh/tools/utilities.py` with comprehensive pattern matching
- Updated all exception handlers in `mcp_server.py` to sanitize errors
- Updated `ssh_client.py` to provide generic error messages (detailed errors in exception chain)
- Comprehensive tests for all sanitization patterns
- Updated documentation with error sanitization details
- **YAML File Size Limits (PR4)**: Added file size validation for YAML configuration files
- Maximum file size limit of 10MB per YAML file (`servers.yml`, `credentials.yml`, `policy.yml`)
- File size validation before parsing to prevent resource exhaustion attacks
- Security event logging for size limit violations
- Added `MAX_YAML_FILE_SIZE` constant (10MB) with clear documentation
- Updated `_load_yaml()` function with size checking logic
- Comprehensive tests for normal, oversized, and edge case file sizes
- Updated documentation with file size limit details
- **Path Traversal Protection (PR1 & PR2)**: Security enhancements to prevent path traversal attacks
- **Secret Path Protection (`_resolve_secret`)**:
- Secret name validation: only alphanumeric characters, dashes, and underscores allowed
- Path normalization and validation to ensure paths stay within `/app/secrets`
- Absolute path rejection for secrets (relative paths only)
- Path traversal pattern detection and blocking (`../`, `..\\`)
- Security event logging for all traversal attempts
- **SSH Key Path Protection (`_resolve_key_path`)**:
- Traversal pattern detection and rejection
- Absolute path validation (must be within `keys_dir`)
- Relative path validation with directory confinement
- Cross-platform support (handles both forward slash and backslash traversal)
- Security event logging for all traversal attempts
- Comprehensive test coverage with 9 new security-focused tests per function
- **File Path Validation (PR3)**: Added file type validation for secret and key paths
- Added `_validate_file_path()` helper function that validates paths are regular files
- Rejects directories (paths must point to files, not directories)
- Rejects symbolic links (symlinks rejected for security)
- Integrated validation into `_resolve_secret()` and `_resolve_key_path()`
- Added comprehensive tests for directory/symlink rejection and regular file validation
- Updated documentation with file type validation requirements
- Path traversal protection documentation
- Comprehensive path traversal protection section in `docs/SECURITY.md`
- Secret name validation documentation with allowed characters and examples
- SSH key path validation documentation with relative/absolute path rules
- Security event logging examples for path traversal attempts
- Updated credentials and configuration documentation with security features
### Fixed
- **Security Fix: SSH Host Key Validation (CWE-295)**: Fixed CodeQL security alert by removing unsafe Paramiko host key policies
- Removed `AcceptPolicy` class and `AutoAddPolicy()` usage which accept unknown host keys
- Always use `RejectPolicy()` for strict host key verification to prevent MITM attacks
- `host_key_auto_add` and `require_known_host=False` are now deprecated and ignored
- Deprecation warnings logged when unsafe configurations are detected
- All SSH connections now require known_hosts entry for security
- Updated documentation to reflect security requirements and migration path
- References CodeQL alert: py/paramiko-missing-host-key-validation
- **CI/CD Workflow Fix**: Fixed lint and build workflows to run on documentation-only PRs
- Removed restrictive `paths:` filter from `pull_request` triggers in `lint.yml` and `build.yml`
- Added `check-changes` job using `dorny/paths-filter` to detect code vs documentation changes
- Made all lint/build/test jobs conditional - they skip gracefully when only documentation changed
- Added `skip-docs-only` job that always succeeds when no code changes detected
- Workflows now always run (satisfies required branch protection checks) while skipping unnecessary jobs
- Prevents "Expected - Waiting for status to be reported" blocking merges on documentation PRs
- **Repository Maintenance**: Added `plan.plan.md` to `.gitignore` to prevent planning documents from being committed
## [0.2.1] - 2025-10-31
### Changed
- Updated Dockerfile to use Python 3.13-slim with pinned SHA256 digest for reproducibility
- Switched from Python 3.14 (pre-release) to stable Python 3.13
- Changed from editable install (`pip install -e .`) to production install (`pip install .`)
### Removed
- Removed `openssh-client` from Docker image (debug tool not needed in production)
- Removed `libffi8` system dependency (not required by Python wheels)
- Removed redundant example configuration file copies in Docker image
- Removed unused PATH modification for user local bin directory
### Fixed
- Fixed trailing whitespace in Dockerfile apt-get command
## [0.2.0] - 2025-10-25
### Added
- **Async Task Support (SEP-1686)**: Complete implementation of asynchronous task execution with real-time progress monitoring
- `ssh_run_async`: Start SSH commands asynchronously with immediate task ID return
- `ssh_get_task_status`: Poll task status with progress percentage and elapsed time
- `ssh_get_task_result`: Retrieve final results with complete output and metadata
- `ssh_get_task_output`: Stream recent output lines from running tasks
- `ssh_cancel_async_task`: Cancel running async tasks mid-execution
- **AsyncTaskManager**: Thread-safe task management with background execution
- Task lifecycle states: pending → running → completed/failed/cancelled/timeout
- Output buffering with line-by-line streaming
- Result storage with configurable TTL (default 5 minutes)
- MCP notification support for task events
- **Policy Configuration Enhancements**:
- `task_result_ttl`: Configurable task result retention (default 300 seconds)
- `task_progress_interval`: Progress update frequency (default 5 seconds)
- Per-host and per-tag overrides for async task settings
- **MCP Notifications**: Server-initiated notifications for task state changes
- `tasks/created`: Task started
- `tasks/progress`: Periodic progress updates
- `tasks/completed`: Task finished successfully
- `tasks/failed`: Task finished with error
- `tasks/cancelled`: Task was cancelled
- Production-ready Docker Compose configuration (`docker-compose.yml`) that pulls published image from ghcr.io
- Development Docker Compose configuration (`docker-compose.dev.yml`) for local builds
- Smart setup script with auto-detection for dev vs end-user modes
- Enhanced compose documentation with clear production vs development workflows
- YAML Style Guide in `docs/POLICY_REFERENCE.md` with consistent formatting guidelines
- Standardized array formatting rules for improved readability
### Changed
- Renamed docker-compose files to follow convention: `docker-compose.yml` for production (default), `docker-compose.dev.yml` for development
- Updated `compose/setup.sh` to support both dev and end-user workflows with auto-detection
- Refactored compose README to clearly distinguish production and development setup paths
- Updated main README with separate instructions for end users vs developers
- Enforced consistent YAML array formatting across all configuration files:
- Empty arrays: inline format `[]`
- Single items: inline format `["item"]`
- Multiple items: multi-line format with dash syntax
- Updated all documentation examples to follow consistent style guide
- Standardized `aliases` and `tags` arrays in policy rules (multi-line for 2+ items)
- Updated all `servers.yml` tag arrays to multi-line format for consistency
- Refactored all YAML configuration files to follow unified style guidelines
### Removed
- Old `docker-compose.prod.yml` file (consolidated into default `docker-compose.yml`)
### Files Modified
- `compose/docker-compose.yml` (now default production)
- `compose/docker-compose.dev.yml` (new development file)
- `compose/setup.sh` (enhanced with dev/enduser modes)
- `compose/README.md` (completely restructured)
- `README.md` (updated Docker Compose instructions)
- `config/policy.yml`
- `config/servers.yml`
- `examples/example-policy.yml`
- `examples/example-servers.yml`
- `docs/POLICY_EXAMPLES.md`
- `docs/POLICY_REFERENCE.md`
## [0.1.3] - 2025-01-27
### Added
- Comprehensive policy configuration documentation
- `docs/POLICY_REFERENCE.md` - Complete technical reference with all configuration options, types, defaults, and examples
- `docs/POLICY_EXAMPLES.md` - 10+ practical configuration examples for different environments and use cases
- `docs/POLICY_SECURITY.md` - Security best practices, troubleshooting guide, and incident response procedures
- Policy documentation links in main README.md
- Cross-references between all policy documentation files
- Comprehensive tables for all policy configuration sections (limits, network, rules, overrides)
- Real-world examples for production, development, staging, Proxmox, and network-restricted environments
- Security checklists and troubleshooting guides
- Glob pattern matching syntax documentation
- Rule evaluation order and precedence explanations
### Changed
- Updated README.md to include dedicated "Policy Configuration" section with links to comprehensive documentation
- Enhanced documentation structure with consistent cross-references between policy docs
## [0.1.2] - 2025-10-24
### Fixed
- Fixed SSH host key handling when `require_known_host` is set to false
- Added `AcceptPolicy` class to handle unknown host keys without saving them
- Resolved "Server not found in known_hosts" error when using permissive host key policies
- Improved SSH connection reliability for environments with dynamic host keys
### Changed
- Enhanced SSH client logic to properly respect `require_known_host: false` setting
- Updated host key policy handling to support three modes: strict, permissive, and auto-add
## [0.1.1] - 2025-10-22
### Fixed
- Fixed Docker build issues in CI/CD pipeline
- Resolved linting and formatting errors for automated workflows
- Fixed Docker test step to properly load built images
- Corrected exception chaining in SSH client error handling
- Fixed loop variable binding issues in progress callbacks
### Changed
- Updated Python base image to 3.14-slim for latest security patches
- Improved Docker build process with better .dockerignore configuration
- Enhanced CI/CD workflows with proper dependency management
- Updated development dependencies (black, ruff, mypy, pytest)
### Added
- Automated dependency management with Dependabot
- Comprehensive CI/CD pipeline with linting, testing, and Docker builds
- Automated code formatting and type checking
- Docker Compose setup with automated configuration
- Example configuration files and setup scripts
## [0.1.0] - 2025-10-21
### Added
- Initial release of MCP SSH Orchestrator
- Core MCP server implementation with STDIO transport
- SSH command execution with Paramiko
- Policy-based access control engine
- Allow/deny rules with glob pattern matching
- Per-alias and per-tag limit overrides
- Deny substrings for dangerous commands
- Network security controls
- IP allowlist/blocklist with CIDR support
- Pre-connect DNS resolution verification
- Post-connect peer IP validation
- Credential management
- SSH key-based authentication
- Password-based authentication
- Docker secrets integration
- Environment variable support for secrets
- Configuration system
- YAML-based configuration (servers, credentials, policy)
- Hot-reload capability
- Example configuration files
- MCP Tools
- `ssh_ping` - Health check
- `ssh_list_hosts` - List configured hosts
- `ssh_describe_host` - Get host details
- `ssh_plan` - Dry-run command with policy check
- `ssh_run` - Execute command on single host
- `ssh_run_on_tag` - Execute command on tagged hosts
- `ssh_cancel` - Cancel running commands
- `ssh_reload_config` - Hot-reload configuration
- Execution features
- Real-time streaming output
- Cancellation support
- Timeout enforcement
- Output size limits
- Progress callbacks
- Docker support
- Multi-stage Dockerfile
- Non-root user (UID 10001)
- Health checks
- Docker Compose configuration
- Audit logging
- JSON-formatted logs to stderr
- Policy decisions
- Execution metrics
- Network events
- Documentation
- Comprehensive README
- Example configurations
- Docker Desktop integration guide
- Docker MCP Registry compliance
- Registry-compliant server.json metadata
- Proper versioning and tagging
### Security
- Host key verification with known_hosts
- Network egress controls
- Deny-by-default policy model
- Audit trail for all commands
- Read-only container mounts
- Non-root container execution