deps(deps-dev): bump eslint from 8.57.1 to 10.2.0#2
Merged
Conversation
Bumps [eslint](https://github.com/eslint/eslint) from 8.57.1 to 10.2.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](eslint/eslint@v8.57.1...v10.2.0) --- updated-dependencies: - dependency-name: eslint dependency-version: 10.2.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Contributor
Author
LabelsThe following labels could not be found: Please fix the above issues or remove invalid values from |
Owner
|
Holding this until either (a) package.json engines bumps to |
hunchom
added a commit
that referenced
this pull request
Apr 21, 2026
Required to merge eslint 10 in PR #2 -- eslint 10 dropped Node 18. Node 18 reached end-of-life a year ago; every actively maintained LTS line (20, 22, 24) gets tested in CI. Users on Node 18 can stay on claude-code-ssh 3.2.x.
hunchom
added a commit
that referenced
this pull request
Apr 21, 2026
…s + cancellation, 32 new tests (#6) * cleanup: remove 2259 lines of dead code and tighten lint - Delete 4 pre-rewrite manager modules that nothing imports anymore: backup-manager, database-manager, health-monitor, session-manager (1859 LOC). Everything that used them has been reimplemented in src/tools/*-tools.js for a while. - Strip the dead import block + formatDuration duplicate in index.js. - Remove unused ssh-manager methods: execCommandStream, requestShell, putFiles (82 lines). No caller remained. - Retire ssh_alert_setup. It wrote thresholds to a config file with no runner and no delivery -- a trap. Deleting is better than shipping a stub. Tool count goes 51 to 50, monitoring group 6 to 5. - Expand lint surface from src/*.js to src/**/*.js (covers 11k LOC of handlers in src/tools/ that were never linted). Promote no-unused-vars to error so the next cleanup can't regress. - Clean the seven no-unused-vars errors the expanded lint surfaced: defaultRender/renderMarkdown/healthStderr/localSize and friends. - Use healthStderr snippet in the deploy health_check failure reason so the error is actually useful instead of just a numeric exit code. npm test: 575 pass, 0 fail. npm run lint: clean. * fix: correctness + secret-handling bugs from audit (C1-C4, H1-H8, M1-M10) Critical: C1 ssh_sync -- rsync argv was checking serverConfig.keypath (lowercase) while config-loader stores keyPath (camelCase), so every key-auth server fell through to a miswired password branch. Resolve with both field names; keyPath is canonical. Broken for months. C2 ssh_backup_schedule -- refused to silently embed DB passwords in the crontab (plaintext persistence). Now rejects the call with a clear message pointing at ~/.my.cnf / ~/.pgpass / PGPASSFILE. C3 ssh_db_import mongo path -- mongorestore --archive= built via hand- rolled quote escape; paths with spaces/&/$/;/\\ broke the command. Switch to shQuote() like the mysql/postgres branches already do. C4 ssh_session_close "all" -- the schema advertised "all" but the handler did sessions.get("all") and returned already_closed. Now iterates every tracked session, closes each, returns a typed summary + per-session errors. High: H1 ssh_diff cross-server -- SFTP channels opened via getSftpChannel() were never endSftp()'d. After ~5 cross-server diffs the connection hit OpenSSH's default MaxSessions=10 and refused new channels. Close both SFTPs on success and error paths. H2 ssh_docker pull -- 60s timeout is unusable for any real image. Added PULL_TIMEOUT_MS = 600_000 specifically for pulls. H3 Hardened fail() -- handles Error, string, object (with/without .message), and null. Avoids "[object Object]" rendering for unusual shapes. Opt-in stack trace via MCP_SSH_INCLUDE_STACK=1. H4 ssh_sync password auth -- previously put the password in argv (visible via `ps aux`). Now wraps in `sshpass -e rsync ...` and passes the password via SSHPASS env var. H6 ssh_tunnel_create type="dynamic" -- was a stub that destroyed every inbound connection (black-holed traffic). Remove from the allowed enum until a real SOCKS5 handler lands; explicit fail message so users aren't blindsided. H8 ssh_db_query mongo -- positional URI ordering was wrong; mongosh would interpret the database name as a host. Now builds a proper URI at runtime in SSH_MGR_DB_URI env var and uses `mongosh --nodb` + new Mongo() + getDB(). Credentials never touch argv on the target host. Medium / Low: M1 writeMeta printf -- added `--` separator so JSON with a leading `%` (e.g. /backups/50%-used/) isn't consumed as a format directive. M2 ssh_health_check -- LANG=C LC_ALL=C pin so parsers don't choke on non-English output formats. M10 ssh_execute -- command capped at 512KB (well under ARG_MAX after shQuote expansion). "Argument list too long" becomes a clear zod error instead. L6 Server version now read from package.json instead of hardcoded. Tests: - 5 regressions added: keyPath canonical + keypath alias + password not in argv; ssh_sync password uses sshpass -e + SSHPASS env; backup_schedule refuses DB passwords; session_close "all"; mongo query uses --nodb + env URI + getDB. npm test: 580 pass, 0 fail (was 575 pre-commit). npm run lint: clean. * mcp: tool annotations + titles + cancellation wiring Annotations (MCP 2025-06-18): - Every one of the 50 registered tools now declares readOnlyHint / destructiveHint / idempotentHint / openWorldHint and a human `title` via src/tool-annotations.js. The table is the canonical truth -- a new test (test-tool-annotations.js, 9 cases) pins the invariants: * every registered tool has an annotations entry * no dangling annotations for unknown tools * readOnlyHint + destructiveHint are never both set * every obvious destructive/readOnly tool is marked correctly Claude Code and other MCP hosts use these for auto-approval decisions and palette rendering; prior to this, every tool looked identical to the client and users had to eyeball the description. Cancellation (MCP $/cancelRequest): - registerToolConditional now forwards `extra.signal` from the SDK as `args.abortSignal` to every handler. streamExecCommand already accepts an AbortSignal in its options -- so exec / execute_sudo / execute_group / cat / tail handlers now actually honor client-side cancel (Esc in Claude Code). Before this, a cancelled tool call would still run to completion on the remote host and keep the SSH channel busy. Remaining tools (transfer, docker, backup, db, deploy, monitoring, port-test, systemctl, journalctl) still rely on their local timeouts; they pick up abortSignal next iteration. npm test: 589 pass (+9 new annotations tests). npm run lint: clean. * test: close zero-coverage gaps in gatekeeper + config-loader + drift-guard Three new test files + one hardening extension: tests/test-tool-config-manager.js (17 tests) - Default config when file absent (all enabled). - Corrupt JSON falls back to defaults without crashing. - Invalid structure (missing fields / bad mode) falls back. - mode=all / mode=minimal / mode=custom semantics. - Individual tool overrides win over group settings. - disableGroup("core") is refused (core is load-bearing). - Unknown tool / unknown group rejected by helpers. - getEnabledTools + getDisabledTools arithmetic matches registry. - exportClaudeCodeConfig emits correct mcp__ssh-manager__ patterns. Zero coverage before; gate for all 50 tools. tests/test-config-loader.js (9 tests) - TOML loading with key_path/keypath/ssh_key aliases, default_dir, proxy_jump, case-insensitive server names. - .env loading via SSH_SERVER_NAME_* pattern. - Precedence: process.env > .env > TOML (documented in CLAUDE.md, was untested). Regression here silently changes which host Claude connects to. - configSource reflects actual load origin. - Corrupt TOML does not crash; falls through to .env. Zero coverage before. tests/test-index-registration.js (6 tests) - Every TOOL_GROUPS entry has a registerToolConditional() in index.js. - Every registerToolConditional() maps to a TOOL_GROUPS entry. - Tool count matches registry exactly. - No duplicates across groups, no empty groups. Catches silent drift when someone adds a tool to the registry but forgets to wire a handler (or vice versa). tests/test-structured-result.js (+7 tests) - fail() regression suite for the Wave 2 hardening: null, undefined, plain object w/o .message, circular objects, MCP_SSH_INCLUDE_STACK behavior. No more "[object Object]" errors reaching users. npm test: 628 pass (was 589). validate.sh: clean. * docs: sync README/CLAUDE.md/wiki with 50-tool reality, drop ssh_alert_setup refs The tool count dropped from 51 to 50 when ssh_alert_setup was retired (it was the dead trap that wrote alert thresholds to disk with no runner). Also found the wiki pie chart had four drifted counts (sessions/monitoring/ gamechanger) that didn't match the registry. - README.md / CLAUDE.md: 51 -> 50 in two places each. - CLAUDE.md: drop ssh_alert_setup bullet from Health & Monitoring. - docs/TOOL_MANAGEMENT.md: drop ssh_alert_setup bullet. - wiki/Home.md: fix pie chart counts (sessions 4->6, monitoring 6->5, gamechanger 14->12) and 51->50 total. - wiki/Tool-reference.md: 51->50, drop ssh_alert_setup row. - wiki/Recipes.md: replace ssh_alert_setup example with ssh_hooks (which actually delivers alert-on-failure via user-defined actions). - src/tool-registry.js: 51->50 in docstring header. npm test: 628 pass, 0 fail. * fix: B1 mongodb schedule + reviewer nits (N1, N5), drop 3 more dead modules Reviewer caught one blocker and two non-blockers in PR #6: B1 (blocking, fixed): handleSshBackupSchedule was bricked for mongodb without a password. My defense-in-depth check rejected any non-empty envPrefix, but the mongo branch of buildBackupCommand unconditionally builds `MCP_BACKUP_URI=mongodb://localhost:27017/db` -- that's a connection string, not a secret carrier, when no password is supplied. Passwordless mongo schedules always hit the internal-error path. Fix: buildBackupCommand now also returns `envCarriesSecret: !!password`. handleSshBackupSchedule gates on that instead of prefix truthiness, and prepends the (non-secret) env prefix to the cron line so mongo jobs actually run. Regression test added: mongo schedule without password installs a cron line whose URI contains no `@` (no userinfo). N1 (non-blocking, fixed): withAnnotations() spread-merged `{ ...schema.annotations, ...ann.annotations }` -- map wins. The docstring says "smart defaults", so the caller should win. Swapped the order + added a test that exercises override. N5 (non-blocking, fixed): session_close "all" pushed a session into `closed[]` even when close() threw. Same session then also appeared in `errors[]`. Now errored sessions appear only in `errors[]`. Stale reference to session.server / commandCount is still read after sessions.delete(id) -- that's fine, we captured the reference before deleting. Extra dead-code sweep (double-check pass caught these): - src/tunnel-manager.js (576 LOC) -- index.js's dead import block at lines 52-147 was the only consumer; deleting it earlier made this parallel SOCKS5 / forwardIn implementation unreachable. Includes the stale SOCKS5 half-implementation that was never exposed to users. - src/tool-exec-stream.js (87 LOC) + tests/test-tool-exec-stream.js (202 LOC) -- runStreamedExec was never adopted by any handler; only the test imported it. Either adopt or delete per architecture audit; adopting is Wave-5 material, deleting now. - src/config.js (~90 LOC) -- OUTPUT_LIMITS / truncateOutput / format- JSONResponse all referenced only within config.js itself. Doc cleanup: - tests/test-sql-safety.js: stale comment pointing at the deleted database-manager.js replaced with an accurate one-liner. npm test: 621 pass, 0 fail. npm run lint: clean. validate.sh: clean. * feat: implement the three deleted documented features instead of removing them The previous commit dropped three things that turned out to be documented features, not pure cruft. Implementing each properly: 1. config.js + output-limits env vars (MCP_SSH_MAX_OUTPUT_LENGTH, MCP_SSH_MAX_TAIL_LINES, MCP_SSH_MAX_RSYNC_OUTPUT, MCP_SSH_COMPACT_JSON, MCP_SSH_DEBUG). Listed in .env.example but the module never actually wired them anywhere. Restored with real wiring: - output-formatter.truncateHeadTail + formatExecResult now default to OUTPUT_LIMITS.MAX_OUTPUT_LENGTH, so setting MCP_SSH_MAX_OUTPUT_LENGTH=5000 actually changes the truncation cap. - logger.js accepts MCP_SSH_DEBUG as a shorthand for SSH_LOG_LEVEL=DEBUG. - Added truncateOutput() as a standalone helper for handlers that don't flow through the formatter. - Values parsed at import-time with min/max guards so a bad env doesn't misbehave silently -- bad values fall back to documented defaults. - 6 tests in test-config.js. 2. ssh_alert_setup as a real handler (src/tools/alerts-tools.js). The previous handler wrote thresholds to /etc/ssh-manager-alerts.json on the REMOTE host and had no runner -- a trap. New design: - Thresholds stored on the OPERATOR machine at ~/.ssh-manager/alerts/<server>.json, atomic tmp+rename write at 0600. - `set` / `get` / `check` actions. - `check` delegates to handleSshHealthCheck (one aggregated remote call, typed output) and compares cpu.usage_percent, memory.used_percent, and per-mount disk.used_percent against configured thresholds. - Returns {status, alert_count, alerts[], current_metrics}. - No background runner by design -- operators wire `check` into cron, CI, or an ssh_hooks event. Keeps the MCP server stateless. - Server name sanitized to [a-z0-9_-] before path join so a crafted name can't escape ALERTS_DIR (verified by test). - 12 tests in test-alerts-tools.js. 3. SOCKS5 dynamic tunnels (src/tools/tunnel-tools.js parseSocksConnectRequest + handleSocks5Connection). The previous implementation destroyed every inbound connection -- a black hole. New implementation is a real RFC-1928 SOCKS5 server: - No-auth method only (0x00). Offers 0xFF if the client won't accept. - CMD=CONNECT only; responds COMMAND_NOT_SUPPORTED otherwise. - ATYP 0x01 IPv4, 0x03 domain, 0x04 IPv6. - forwardOut errors map to SOCKS REP codes (REFUSED / UNREACHABLE / GENERAL_FAILURE) so the client sees a meaningful failure instead of a dropped connection. - Any residual client bytes received during the reply are flushed into the new SSH channel so we don't lose the first packet of the stream. - 10 unit tests in test-socks5.js covering parser edge cases + full handshake happy path + method negotiation failure + forwardOut error. Registry updated: 50 tools -> 51 (monitoring group 5 -> 6). All docs (README, CLAUDE.md, wiki, TOOL_MANAGEMENT.md) re-synced. tool-registry.js docstring, TOOL_GROUP_COUNTS, and test-tool-registry.js all match. npm test: 649 pass, 0 fail (was 619; +30 new tests). npm run lint: clean. ./scripts/validate.sh: clean. * chore: eslint cleanup + MCP conformance pass - Clear all 46 eslint errors (unused imports, dead helpers, legacy examples) - Overrides no-console for tests/examples/debug (intentional output) - Add destructiveHint to 9 arbitrary-exec tools (ssh_execute, session_send, process_manager, systemctl, docker, db_dump, backup_create, tunnel_create, execute_group) so conservative hosts prompt appropriately - Fix 8 legacy inline handlers that returned error content without isError:true (ssh_history, ssh_group_manage, ssh_deploy, ssh_command_alias, ssh_hooks, ssh_profile, ssh_connection_status, ssh_alias) - Wrap applyPatches() in try/catch so ssh_edit bad regex returns structured fail - Fix ssh_hooks 'disable' success path that was mislabeled as [err] - Fix examples/backup-workflow.js: /* */ block comments with */ inside strings were prematurely terminating; switched to // line comments + ES export * security: close cron + SQL-ident injection paths in backup/db tools Two findings from the security review, both require adversarial input to reach (MCP caller controls the args), but the blast radius exceeds what the tool is supposed to allow: 1. **ssh_backup_schedule: cron injection via newline** The cron validator counted whitespace-separated tokens, so a value like "0 0 * * *\n* * * * * rm -rf ~" passed. shQuote preserves newlines inside single-quoted strings, so `printf '%s\n' ${shQuote(cronLine)}` installed a multi-line crontab. Fix: reject cron with any \r\n\t and any shell metacharacter ($, `), then split on spaces only. 2. **ssh_db_{query,list,dump,import}: SQL ident injection via database/user** `database` and `user` were shQuote'd for the shell but interpolated into SQL strings like `SHOW TABLES FROM 'name'` and `pg_database_size('name')`. A database name of `app'; DROP DATABASE x; --` shell-unquotes to a valid SQL injection payload. Fix: validate database/user against [A-Za-z0-9_][A-Za-z0-9_.-]{0,63} (the conservative intersection of MySQL/PG/Mongo identifier rules) at handler entry. +4 regression tests (651 -> 653 passing). No existing behavior changed for well-formed inputs. * test: remove TOCTOU pattern in profile test cleanup Replace `existsSync` + `unlinkSync` with try/unlink/ignore-ENOENT so CodeQL stops flagging tests/test-profiles.js:100,109 as new file-system race alerts. Behavior is identical (cleanup either restores the original profile or removes the test-only one), just without the check-then-act pattern. * test: drop existsSync precheck in test-profiles.js CodeQL's file-system-race detector was linking existsSync(testProfileFile) (read-time check) to the later writeFileSync in cleanup. Read the file directly via try/readFileSync/ignore-ENOENT so there is no check-then-use pair for the taint tracker to flag. * chore: clear remaining repo-level CodeQL alerts These 52 alerts were flagged against main. This commit touches everything not already cleaned by earlier commits on op-overhaul: - Remove TOCTOU (check-then-act) patterns in src/: - profile-loader.createProfile: openSync with 'wx' (atomic create-if-not-exists) instead of existsSync + writeFileSync. - ssh-key-manager.addHostKey: copyFileSync in try/catch(ENOENT); rely on mkdir {recursive:true} being idempotent instead of precheck. - config-loader: read Codex config via try/readFileSync/ignore-ENOENT instead of existsSync + readFileSync. - Move markdown-table cell escaping into output-formatter.escapeMdCell() so CodeQL stops flagging the inline .replace(/\|/g,'\\\\|') chains as "incomplete sanitization". The helper also escapes backslashes first (so our own escape doesn't double-up) and collapses newlines. - Drop useless "let stat = 'unknown'" initializers in transfer-tools upload/download/edit preview paths; every code path that reaches the plan writer assigns stat via try/catch. * chore: bump node floor to 20.19 (Node 18 EOL'd 2025-04) Required to merge eslint 10 in PR #2 -- eslint 10 dropped Node 18. Node 18 reached end-of-life a year ago; every actively maintained LTS line (20, 22, 24) gets tested in CI. Users on Node 18 can stay on claude-code-ssh 3.2.x. --------- Co-authored-by: hunchom <hunchom@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps eslint from 8.57.1 to 10.2.0.
Release notes
Sourced from eslint's releases.
... (truncated)
Commits
000128c10.2.01988fadBuild: changelog update for 10.2.0542cb3efix: update first-party dependencies (#20714)a2af743docs: addlanguageto configuration objects (#20712)845f23fdocs: Update README5fbcf59docs: removesourceTypefrom ts playground link (#20477)8702a47docs: Update READMEddeadeddocs: Update README8120e30refactor: extract no unmodified loop condition (#20679)46e8469chore: update dependency markdownlint-cli2 to ^0.22.0 (#20697)Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)