Skip to content

Commit a347e6e

Browse files
committed
remove support for internal SSH tunnels
which have enjoyed a lengthy deprecation cycle. We may reimplement this functionality in the future without Paramiko. Incidentally apply the same scheme check to DSNs without --dsn as DSNs with --dsn. Though it isn't clear that all of the schemes currently accepted should be. Fixes #1464. Preparation for release 2.0.
1 parent a2ffb63 commit a347e6e

22 files changed

Lines changed: 54 additions & 768 deletions

AGENTS.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ A command line client for MySQL with auto-completion and syntax highlighting.
3939
├── mycli/packages/hybrid_redirection.py # implementation of shell-style redirects
4040
├── mycli/packages/interactive_utils.py # utilities for confirming on destructive statements
4141
├── mycli/packages/key_binding_utils.py # handlers for key bindings and related special commands
42-
├── mycli/packages/paramiko_stub/ # stub in case the Paramiko library is not installed
4342
├── mycli/packages/sql_utils.py # utilities for parsing SQL statements
4443
├── mycli/packages/ptoolkit/ # extends prompt_toolkit
4544
├── mycli/packages/special/ # implementation of mycli special commands

mycli/cli_runner.py

Lines changed: 5 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@
1414
from mycli.main_modes.checkup import main_checkup
1515
from mycli.main_modes.execute import main_execute_from_cli
1616
from mycli.main_modes.list_dsn import main_list_dsn
17-
from mycli.main_modes.list_ssh_config import main_list_ssh_config
1817
from mycli.packages.cli_utils import is_valid_connection_scheme
19-
from mycli.packages.ssh_utils import read_ssh_config
2018

2119
if TYPE_CHECKING:
2220
from mycli.main import CliArgs
@@ -73,30 +71,9 @@ def run_from_cli_args(cli_args: 'CliArgs', client_factory: ClientFactory) -> Non
7371
fg="yellow",
7472
)
7573

76-
# ssh_port and ssh_config_path have truthy defaults and are not included
77-
if (
78-
any([
79-
cli_args.ssh_user,
80-
cli_args.ssh_host,
81-
cli_args.ssh_password,
82-
cli_args.ssh_key_filename,
83-
cli_args.list_ssh_config,
84-
cli_args.ssh_config_host,
85-
])
86-
and not cli_args.ssh_warning_off
87-
):
88-
click.secho(
89-
f"Warning: The built-in SSH functionality is deprecated and will be removed in a future release. See issue {ISSUES_URL}/1464",
90-
err=True,
91-
fg="red",
92-
)
93-
9474
if cli_args.list_dsn:
9575
sys.exit(main_list_dsn(mycli))
9676

97-
if cli_args.list_ssh_config:
98-
sys.exit(main_list_ssh_config(mycli, cli_args))
99-
10077
if 'MYSQL_UNIX_PORT' in os.environ:
10178
# deprecated 2026-03
10279
click.secho(
@@ -161,6 +138,11 @@ def run_from_cli_args(cli_args: 'CliArgs', client_factory: ClientFactory) -> Non
161138
mycli.dsn_alias = cli_args.dsn
162139

163140
if dsn_uri:
141+
is_valid_scheme, scheme = is_valid_connection_scheme(dsn_uri)
142+
if not is_valid_scheme:
143+
click.secho(f'Error: Unknown connection scheme provided for DSN URI ({scheme}://)', err=True, fg='red')
144+
sys.exit(1)
145+
164146
uri = urlparse(dsn_uri)
165147
if not database:
166148
database = uri.path[1:] # ignore the leading fwd slash
@@ -255,23 +237,6 @@ def run_from_cli_args(cli_args: 'CliArgs', client_factory: ClientFactory) -> Non
255237
else:
256238
ssl = None
257239

258-
if cli_args.ssh_config_host:
259-
ssh_config = read_ssh_config(cli_args.ssh_config_path).lookup(cli_args.ssh_config_host)
260-
ssh_host = cli_args.ssh_host if cli_args.ssh_host else ssh_config.get("hostname")
261-
ssh_user = cli_args.ssh_user if cli_args.ssh_user else ssh_config.get("user")
262-
if ssh_config.get("port") and cli_args.ssh_port == 22:
263-
# port has a default value, overwrite it if it's in the config
264-
ssh_port = int(ssh_config.get("port"))
265-
else:
266-
ssh_port = cli_args.ssh_port
267-
ssh_key_filename = cli_args.ssh_key_filename if cli_args.ssh_key_filename else ssh_config.get("identityfile", [None])[0]
268-
else:
269-
ssh_host = cli_args.ssh_host
270-
ssh_user = cli_args.ssh_user
271-
ssh_port = cli_args.ssh_port
272-
ssh_key_filename = cli_args.ssh_key_filename
273-
274-
ssh_key_filename = ssh_key_filename and os.path.expanduser(ssh_key_filename)
275240
# Merge init-commands: global, DSN-specific, then CLI
276241
init_cmds: list[str] = []
277242
# 1) Global init-commands
@@ -391,11 +356,6 @@ def run_from_cli_args(cli_args: 'CliArgs', client_factory: ClientFactory) -> Non
391356
socket=cli_args.socket,
392357
local_infile=cli_args.local_infile,
393358
ssl=ssl,
394-
ssh_user=ssh_user,
395-
ssh_host=ssh_host,
396-
ssh_port=ssh_port,
397-
ssh_password=cli_args.ssh_password,
398-
ssh_key_filename=ssh_key_filename,
399359
init_command=combined_init_cmd,
400360
unbuffered=cli_args.unbuffered,
401361
character_set=cli_args.character_set,

mycli/client_connection.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,6 @@ def connect(
5454
character_set: str | None = "",
5555
local_infile: bool | None = False,
5656
ssl: dict[str, Any] | None = None,
57-
ssh_user: str | None = "",
58-
ssh_host: str | None = "",
59-
ssh_port: int = 22,
60-
ssh_password: str | None = "",
61-
ssh_key_filename: str | None = "",
6257
init_command: str | None = "",
6358
unbuffered: bool | None = None,
6459
use_keyring: bool | None = None,
@@ -200,11 +195,6 @@ def connect(
200195
"character_set": character_set,
201196
"local_infile": use_local_infile,
202197
"ssl": ssl_config_or_none,
203-
"ssh_user": ssh_user,
204-
"ssh_host": ssh_host,
205-
"ssh_port": int(ssh_port) if ssh_port else None,
206-
"ssh_password": ssh_password,
207-
"ssh_key_filename": ssh_key_filename,
208198
"init_command": init_command,
209199
"unbuffered": unbuffered,
210200
}

mycli/completion_refresher.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,6 @@ def _bg_refresh(
7171
e.character_set,
7272
e.local_infile,
7373
e.ssl,
74-
e.ssh_user,
75-
e.ssh_host,
76-
e.ssh_port,
77-
e.ssh_password,
78-
e.ssh_key_filename,
7974
)
8075
except pymysql.err.OperationalError:
8176
return

mycli/main.py

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -86,44 +86,6 @@ class CliArgs:
8686
type=click.Path(),
8787
help='File or FIFO path containing the password to connect to the db if not specified otherwise.',
8888
)
89-
ssh_user: str | None = clickdc.option(
90-
type=str,
91-
help='User name to connect to ssh server.',
92-
)
93-
ssh_host: str | None = clickdc.option(
94-
type=str,
95-
help='Host name to connect to ssh server.',
96-
)
97-
ssh_port: int = clickdc.option(
98-
type=int,
99-
default=22,
100-
help='Port to connect to ssh server.',
101-
)
102-
ssh_password: str | None = clickdc.option(
103-
type=str,
104-
help='Password to connect to ssh server.',
105-
)
106-
ssh_key_filename: str | None = clickdc.option(
107-
type=str,
108-
help='Private key filename (identify file) for the ssh connection.',
109-
)
110-
ssh_config_path: str = clickdc.option(
111-
type=str,
112-
help='Path to ssh configuration.',
113-
default=os.path.expanduser('~') + '/.ssh/config',
114-
)
115-
ssh_config_host: str | None = clickdc.option(
116-
type=str,
117-
help='Host to connect to ssh server reading from ssh configuration.',
118-
)
119-
list_ssh_config: bool = clickdc.option(
120-
is_flag=True,
121-
help='list ssh configurations in the ssh config (requires paramiko).',
122-
)
123-
ssh_warning_off: bool = clickdc.option(
124-
is_flag=True,
125-
help='Suppress the SSH deprecation notice.',
126-
)
12789
ssl_mode: str = clickdc.option(
12890
type=click.Choice(['auto', 'on', 'off']),
12991
help='Set desired SSL behavior. auto=preferred if TCP/IP, on=required, off=off.',

mycli/main_modes/list_ssh_config.py

Lines changed: 0 additions & 27 deletions
This file was deleted.

mycli/packages/cli_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def is_valid_connection_scheme(text: str) -> tuple[bool, str | None]:
1515
if "://" not in text:
1616
return False, None
1717
scheme = text.split("://")[0]
18-
if scheme not in ("mysql", "mysqlx", "tcp", "socket", "ssh"):
18+
if scheme not in ("mysql", "mysqlx", "tcp", "socket"):
1919
return False, scheme
2020
else:
2121
return True, None

mycli/packages/paramiko_stub/__init__.py

Lines changed: 0 additions & 36 deletions
This file was deleted.

mycli/packages/ssh_utils.py

Lines changed: 0 additions & 27 deletions
This file was deleted.

mycli/schema_prefetcher.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,6 @@ def _make_executor(self) -> SQLExecute:
224224
sqlexecute.character_set,
225225
sqlexecute.local_infile,
226226
sqlexecute.ssl,
227-
sqlexecute.ssh_user,
228-
sqlexecute.ssh_host,
229-
sqlexecute.ssh_port,
230-
sqlexecute.ssh_password,
231-
sqlexecute.ssh_key_filename,
232227
)
233228

234229
def _invalidate_app(self) -> None:

0 commit comments

Comments
 (0)