diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index e463de1..d9ce0e5 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "home-lab-developer-tools", "displayName": "Home Lab Developer Tools", - "version": "0.13.2", + "version": "0.14.0", "description": "Home lab and Raspberry Pi workflows for Cursor, Claude Code, and MCP-compatible editors - 22 skills, 11 rules, and 50 MCP tools for managing Docker Compose stacks, monitoring, DNS, reverse proxy, networking, backups, disaster recovery, security auditing, logs, notifications, OS management, certificates, multi-node, diagnostics, and system administration on a Raspberry Pi home lab via SSH.", "author": { "name": "TMHSDigital", diff --git a/.env.example b/.env.example index 749d8ba..2173fbc 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,7 @@ # Raspberry Pi SSH connection -HOMELAB_PI_HOST=raspi5.local -HOMELAB_PI_USER=tmhs -HOMELAB_PI_KEY_PATH=~/.ssh/id_ed25519_pi +HOMELAB_PI_HOST=raspberrypi.local +HOMELAB_PI_USER=pi +HOMELAB_PI_KEY_PATH=~/.ssh/id_ed25519 # Compose project directory on the Pi HOMELAB_COMPOSE_DIR=/opt/homelab/docker @@ -35,7 +35,11 @@ HOMELAB_BACKUP_REPO=/mnt/backup/restic # HOMELAB_NTFY_PORT=8080 # Multi-node support (JSON object mapping node names to SSH config) -# HOMELAB_NODES='{"nas":{"host":"nas.local","user":"admin","keyPath":"~/.ssh/id_ed25519_nas"},"pi-zero":{"host":"pizero.local","user":"pi","keyPath":"~/.ssh/id_ed25519_pz"}}' +# HOMELAB_NODES='{"nas":{"host":"nas.local","user":"admin","keyPath":"~/.ssh/id_ed25519"},"pi-zero":{"host":"pizero.local","user":"pi","keyPath":"~/.ssh/id_ed25519"}}' # Ansible inventory path for node discovery (default /etc/ansible/hosts) # HOMELAB_ANSIBLE_INVENTORY=/etc/ansible/hosts + +# Safety overrides +# HOMELAB_DRY_RUN=true # When set, execSSH prints what it would run without connecting +# HOMELAB_ALLOW_DANGEROUS_COMMANDS=true # Bypasses the runtime command guard (use with caution) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index e897f01..c34cc78 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - - uses: actions/dependency-review-action@v4 + - uses: actions/dependency-review-action@v5 with: fail-on-severity: high comment-summary-in-pr: always diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 26ef6a1..f5b9c21 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -28,6 +28,6 @@ jobs: --exclude "localhost" --exclude "127.0.0.1" --exclude "example.com" - --exclude "raspi5.local" + --exclude "raspberrypi.local" "**/*.md" "**/*.mdc" diff --git a/CHANGELOG.md b/CHANGELOG.md index ef637d8..4817429 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.14.0] - 2026-05-22 + +### Added + +- Runtime command safety guard in `execSSH` -- blocks catastrophic patterns (`rm -rf /`, `mkfs` on block devices, `dd` to block devices, fork bomb, `chmod -R 777 /`, curl/wget pipe to shell, `poweroff`/`halt`/`shutdown -h`) before opening an SSH connection. Override with `HOMELAB_ALLOW_DANGEROUS_COMMANDS=true`. +- `HOMELAB_DRY_RUN` mode -- when set, `execSSH` returns a description string without connecting. Unsafe commands are still rejected in dry-run mode. +- `UnsafeCommandError` class in `utils/errors.ts` for runtime guard rejections. +- Shared `confirmParam` and `confirmCancelled` helpers in `utils/confirm-param.ts` consumed by all confirm-gated tools. +- `mcp-server/src/utils/__tests__/ssh-guard.test.ts` -- unit tests for the command guard and dry-run mode using the real module (no mock). + +### Changed + +- `homelab_serviceRestart`, `homelab_composeUp`, and `homelab_composeDown` now require `confirm=true` to proceed. Calls without it return a cancellation message and make no changes. +- Default SSH host changed from personal hostname to generic `raspberrypi.local`; default user changed from personal username to `pi`. Override via `HOMELAB_PI_HOST` and `HOMELAB_PI_USER`. +- All confirm-gated tools now use the shared `confirmParam`/`confirmCancelled` helpers for consistent messaging (standardizes "aborted" -> "cancelled" in `certRenew` and `nodeExec`). +- `composePull` remains ungated (pull only downloads images, does not change running state). + ## [0.13.2] - 2026-04-26 See [release notes](https://github.com/TMHSDigital/Home-Lab-Developer-Tools/releases/tag/v0.13.2) for details. diff --git a/CLAUDE.md b/CLAUDE.md index 53544fe..50ef9a9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,7 +12,7 @@ Home Lab Developer Tools integrates home lab and Raspberry Pi workflows into AI- This is a monorepo -- the skills, rules, and companion MCP server live in the same repository. The MCP server connects to a Raspberry Pi via SSH to execute commands. -**Version:** 0.13.2 +**Version:** 0.14.0 **License:** CC-BY-NC-ND-4.0 **npm:** @tmhs/homelab-mcp **Author:** TMHSDigital @@ -179,6 +179,13 @@ npm install -g @tmhs/homelab-mcp - Skills use kebab-case directory names with YAML frontmatter (`name`, `description`, `tools`). - Rules use kebab-case filenames with `description` and `alwaysApply` frontmatter. +## Security + +- Tools that change running state require `confirm=true`: `homelab_piReboot`, `homelab_backupRun`, `homelab_backupRestore`, `homelab_volumeBackup`, `homelab_certRenew`, `homelab_nodeExec`, `homelab_serviceRestart`, `homelab_composeUp`, `homelab_composeDown`. Use the shared `confirmParam` and `confirmCancelled` helpers from `utils/confirm-param.ts`. +- `execSSH()` runs `assertCommandSafe()` before opening any SSH connection. This blocks catastrophic patterns (`rm -rf /`, `mkfs` on block devices, fork bombs, `poweroff`, etc.). Override with `HOMELAB_ALLOW_DANGEROUS_COMMANDS=true`. +- `HOMELAB_DRY_RUN=true` makes `execSSH` return a description string instead of connecting. The command guard still runs in dry-run mode. +- No personal SSH usernames, hostnames, or key names in code or docs. Use `pi` / `raspberrypi.local` / `~/.ssh/id_ed25519` as generic defaults. + ## Release Hygiene When preparing a new release version, ALL of the following files must be updated to reflect the new version number, tool/skill/rule counts, and any new entries: diff --git a/README.md b/README.md index 2975352..d917af5 100644 --- a/README.md +++ b/README.md @@ -146,9 +146,9 @@ Add to your Cursor MCP config (`.cursor/mcp.json`): "args": ["./mcp-server/dist/index.js"], "cwd": "/Home-Lab-Developer-Tools", "env": { - "HOMELAB_PI_HOST": "raspi5.local", - "HOMELAB_PI_USER": "tmhs", - "HOMELAB_PI_KEY_PATH": "~/.ssh/id_ed25519_pi" + "HOMELAB_PI_HOST": "raspberrypi.local", + "HOMELAB_PI_USER": "pi", + "HOMELAB_PI_KEY_PATH": "~/.ssh/id_ed25519" } } } diff --git a/ROADMAP.md b/ROADMAP.md index d096218..e388411 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -16,6 +16,7 @@ | v0.10.0 | Testing Infrastructure | +2 | -- | -- | 50 | | v0.11.0 | Documentation Site | -- | -- | -- | 50 | | v0.12.0 | Polish and Hardening | +2 | -- | -- | 52 | +| v0.14.0 | Security Hardening | -- | -- | -- | 50 | | **v1.0.0** | **Stable Release** | -- | -- | -- | **52** | --- @@ -215,6 +216,18 @@ Real test coverage before v1.0. --- +## v0.14.0 - Security Hardening + +- [x] Runtime command safety guard in `execSSH` blocking catastrophic patterns +- [x] `HOMELAB_DRY_RUN` env var for testing without SSH connections +- [x] Confirm gate extended to `homelab_serviceRestart`, `homelab_composeUp`, `homelab_composeDown` +- [x] Shared `confirmParam`/`confirmCancelled` helpers used by all gated tools +- [x] Personal SSH defaults replaced with generic `raspberrypi.local` / `pi` placeholders +- [x] `UnsafeCommandError` error class for guard rejections +- [x] Unit tests for command guard and dry-run mode + +--- + ## v0.11.0 - Documentation Site Upgrade GitHub Pages from placeholder to full tool reference. diff --git a/SECURITY.md b/SECURITY.md index afb3cdb..de650f4 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -15,7 +15,25 @@ This project connects to remote hosts via SSH. Security considerations: - SSH private keys must never be committed to the repository - The `.env` file containing connection details is gitignored - MCP tools execute commands on remote hosts -- review tool actions before running -- Tools with destructive actions require explicit `confirm=true` parameters: `homelab_piReboot`, `homelab_backupRun`, `homelab_backupRestore`, `homelab_volumeBackup`, `homelab_certRenew`, `homelab_nodeExec` +- Tools with destructive or state-changing actions require explicit `confirm=true` parameters: `homelab_piReboot`, `homelab_backupRun`, `homelab_backupRestore`, `homelab_volumeBackup`, `homelab_certRenew`, `homelab_nodeExec`, `homelab_serviceRestart`, `homelab_composeUp`, `homelab_composeDown` + +## Runtime Command Guard + +`execSSH` blocks a focused set of catastrophic command patterns before opening an SSH connection: + +- `rm -rf /` (and `--no-preserve-root` variant) +- `mkfs` targeting a block device +- `dd` writing to a block device +- Fork bomb (`:(){ :|:& };:`) +- `chmod -R 777 /` +- Piping a remote download to a shell (`curl ... | sh`, `wget ... | bash`) +- `shutdown -h`, `halt`, `poweroff` (note: `shutdown -r` used by `homelab_piReboot` is explicitly allowed) + +To bypass the guard (not recommended): set `HOMELAB_ALLOW_DANGEROUS_COMMANDS=true`. + +## Dry-Run Mode + +Set `HOMELAB_DRY_RUN=true` to make `execSSH` print what it would execute without opening an SSH connection. Unsafe commands are still rejected in dry-run mode. ## Best Practices diff --git a/docs/index.html b/docs/index.html index fcb4beb..fcf5408 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1479,11 +1479,11 @@

Related Tools