v1.8.23: upgrade ssh.py + skill for secure Claude Code integration
- Add --info (safe server details without credentials) - Add --set-note (update server notes for context) - Add --no-sudo flag documentation in skill - Fix --add leaking user@ip:port in output - Add WARNING to --list-full, forbid in skill - Add notes column to --list output - Update skill: portable path ~/.server-connections/, security rules, behavior docs - Update CLAUDE.md: security section, architecture, dev commands, doc references Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
50
tools/ssh.py
50
tools/ssh.py
@@ -12,6 +12,8 @@ Usage:
|
||||
python ssh.py ALIAS --ping
|
||||
python ssh.py --list
|
||||
python ssh.py --status
|
||||
python ssh.py --info ALIAS # full info (no passwords)
|
||||
python ssh.py --set-note ALIAS "desc" # update server notes
|
||||
python ssh.py --add ALIAS IP PORT USER PASSWORD [--note "desc"]
|
||||
python ssh.py --remove ALIAS
|
||||
"""
|
||||
@@ -229,6 +231,9 @@ def ping_server(server: dict):
|
||||
def list_servers(full=False):
|
||||
_, servers = load_servers()
|
||||
if full:
|
||||
# WARNING: full mode shows sensitive data (IP, port, user)
|
||||
# Only for local/manual use, NEVER through AI API
|
||||
print("WARNING: Full mode — contains sensitive data. Do NOT pipe to AI.")
|
||||
print(f"{'Alias':<20} {'IP':<20} {'Port':<8} {'User':<10} {'Key':<6}")
|
||||
print("-" * 64)
|
||||
for alias, s in servers.items():
|
||||
@@ -236,12 +241,31 @@ def list_servers(full=False):
|
||||
print(f"{alias:<20} {s['ip']:<20} {s.get('port', 22):<8} {s.get('user', 'root'):<10} {has_key:<6}")
|
||||
else:
|
||||
# Safe mode: only aliases (no IPs, ports, users)
|
||||
print(f"{'Alias':<20} {'Type':<10} {'Key':<6}")
|
||||
print("-" * 36)
|
||||
print(f"{'Alias':<20} {'Type':<10} {'Key':<6} {'Notes'}")
|
||||
print("-" * 70)
|
||||
for alias, s in servers.items():
|
||||
has_key = "yes" if os.path.exists(SSH_KEY_PATH) else "no"
|
||||
stype = s.get("type", "ssh")
|
||||
print(f"{alias:<20} {stype:<10} {has_key:<6}")
|
||||
notes = s.get("notes", "")
|
||||
print(f"{alias:<20} {stype:<10} {has_key:<6} {notes}")
|
||||
|
||||
|
||||
def server_info(alias: str):
|
||||
"""Show server info safe for AI context — NO ip, user, password, port, totp_secret."""
|
||||
_, servers = load_servers()
|
||||
if alias not in servers:
|
||||
print(f"Unknown: {alias}. Available: {', '.join(servers.keys())}")
|
||||
sys.exit(1)
|
||||
s = servers[alias]
|
||||
has_key = "yes" if os.path.exists(SSH_KEY_PATH) else "no"
|
||||
print(f"Alias: {s['alias']}")
|
||||
print(f"Type: {s.get('type', 'ssh')}")
|
||||
print(f"Key: {has_key}")
|
||||
print(f"Auth: {s.get('auth', 'password')}")
|
||||
print(f"2FA: {'yes' if s.get('totp_secret') else 'no'}")
|
||||
notes = s.get("notes", "")
|
||||
if notes:
|
||||
print(f"Notes: {notes}")
|
||||
|
||||
|
||||
def check_status():
|
||||
@@ -283,7 +307,7 @@ def add_server(args):
|
||||
data["servers"].append(new_server)
|
||||
save_servers(data)
|
||||
update_ssh_config(alias, ip, port, user)
|
||||
print(f"Added: {alias} ({user}@{ip}:{port})")
|
||||
print(f"Added: {alias}")
|
||||
|
||||
try:
|
||||
install_key(new_server)
|
||||
@@ -291,6 +315,20 @@ def add_server(args):
|
||||
print(f"Warning: key not installed ({e}). Run: ssh.py {alias} --install-key")
|
||||
|
||||
|
||||
def set_note(alias: str, note: str):
|
||||
"""Update server notes — safe for AI (no credentials exposed)."""
|
||||
data, servers = load_servers()
|
||||
if alias not in servers:
|
||||
print(f"Unknown: {alias}. Available: {', '.join(servers.keys())}")
|
||||
sys.exit(1)
|
||||
for s in data["servers"]:
|
||||
if s["alias"] == alias:
|
||||
s["notes"] = note
|
||||
break
|
||||
save_servers(data)
|
||||
print(f"OK: notes updated for {alias}")
|
||||
|
||||
|
||||
def remove_server(alias: str):
|
||||
data, servers = load_servers()
|
||||
if alias not in servers:
|
||||
@@ -348,6 +386,10 @@ def main():
|
||||
list_servers(full=True); sys.exit(0)
|
||||
if cmd == "--status":
|
||||
check_status(); sys.exit(0)
|
||||
if cmd == "--info" and len(sys.argv) >= 3:
|
||||
server_info(sys.argv[2]); sys.exit(0)
|
||||
if cmd == "--set-note" and len(sys.argv) >= 4:
|
||||
set_note(sys.argv[2], sys.argv[3]); sys.exit(0)
|
||||
if cmd == "--add":
|
||||
add_server(sys.argv[2:]); sys.exit(0)
|
||||
if cmd == "--remove" and len(sys.argv) >= 3:
|
||||
|
||||
Reference in New Issue
Block a user