Files
zyt/artifacts/private_dify_ssh_20261027.py
2026-10-27 14:03:35 +08:00

89 lines
4.1 KiB
Python

"""Authorized fixed-source collection; password lives only in this process's memory."""
from __future__ import annotations
import argparse
import getpass
import importlib.util
import json
import logging
import socket
import sys
from pathlib import Path
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--username", required=True)
parser.add_argument("--source-ip", required=True)
args = parser.parse_args()
password = getpass.getpass("SSH password (not stored): ")
logging.disable(logging.CRITICAL)
import paramiko
original_client = paramiko.SSHClient
class DirectLanClient(original_client):
def connect(self, hostname, port=22, **kwargs):
if hostname != "192.168.110.111" or port != 22:
raise ValueError("Unexpected SSH destination")
direct = socket.create_connection((hostname, port), timeout=6, source_address=(args.source_ip, 0))
try:
return super().connect(hostname, port=port, sock=direct, **kwargs)
except Exception:
direct.close()
raise
paramiko.SSHClient = DirectLanClient
root = Path(__file__).resolve().parents[1]
destination = root / "artifacts/ai_full_verification_20261027/dify_current_source"
destination.mkdir(parents=True, exist_ok=True)
original = root / "app/artifacts/ai_concurrency/r35_root_source_acquisition"
print("AUTH_READY_FIXED_READONLY_ACTIONS", flush=True)
for line in sys.stdin:
action = line.strip()
if action == "quit":
break
operations = {"inspect", "stage", "imports", "build", "deploy", "rollback", "installed", "health", "logs-safe",
"diagnose-imports", "prepare-deploy", "deployment-status"}
if action not in {"collect", "dependencies"} | operations:
print('{"ok":false,"error_code":"UNKNOWN_ACTION"}', flush=True)
continue
module_name = "collect_sources" if action == "collect" else "collect_dependencies"
try:
if action in operations:
operation_module = "private_dify_ops_actions_20261027.py"
if action == "diagnose-imports":
operation_module = "private_dify_ops_actions_v2_20261027.py"
elif action in {"prepare-deploy", "deploy", "rollback", "deployment-status"}:
operation_module = "private_dify_rollout_actions_20261027.py"
spec = importlib.util.spec_from_file_location("private_dify_ops_actions",
root / "artifacts" / operation_module)
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.RejectPolicy())
try:
client.connect("192.168.110.111", username=args.username, password=password,
look_for_keys=False, allow_agent=False, timeout=6, auth_timeout=6, banner_timeout=6)
summary = module.run_action(client, action, root)
finally:
client.close()
print(json.dumps({"ok": True, "action": action, "summary": summary}), flush=True)
continue
spec = importlib.util.spec_from_file_location("private_dify_" + module_name, original / (module_name + ".py"))
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
module.HERE = destination
# BASE keeps the read-only historical inventory. Output is NEW.
summary = module.collect(username=args.username, password=password)
print(json.dumps({"ok": True, "action": action, "summary": summary}), flush=True)
except Exception as exc:
# Do not print remote stderr, credentials, commands, or source bodies.
print(json.dumps({"ok": False, "action": action, "error_type": type(exc).__name__}), flush=True)
password = ""
if __name__ == "__main__":
main()