Skip to content

fix(cli)!: give OpenSSH back its short flags (-N, -f, -C, -A, -S, -k, -b) #287

Description

@inureyes

Part of the OpenSSH drop-in compatibility epic. Breaking change, targeted at 3.0.

Problem

Seven single-letter flags mean one thing in ssh(1) and something else in bssh. As long as that is true, "drop-in replacement" cannot be true, because the same command line does different things depending on which binary is on PATH.

Flag OpenSSH ssh(1) bssh 2.4.3
-N Do not execute a remote command, used with forwarding --no-prefix, a pdsh output option
-f Go to background after authentication --filter, host subset selection
-C Enable compression --cluster, cluster name from config
-A Enable agent forwarding --use-agent, use the agent for authentication
-S ControlPath for connection multiplexing --sudo-password
-k Disable GSSAPI credential forwarding --fail-fast, a pdsh option
-b bind_address --batch, Ctrl+C handling

The most consequential is -N. bssh already implements -L, -R and -D, and ssh -N -L 8080:host:80 user@host is the single most common port-forwarding idiom there is. In bssh that line currently parses as "disable the hostname prefix" and then tries to open a shell. The suite's dynamic-forward.sh uses -S, -N, -M and -f in one invocation.

-A deserves separate mention because the divergence is security-shaped rather than merely confusing. Someone who reaches for -A expecting OpenSSH's agent forwarding gets authentication-agent use instead and no forwarding happens, which at least fails closed. The reverse habit is the dangerous direction: a bssh user who learns -A as harmless and carries it to ssh enables agent forwarding to a remote host without meaning to.

Governing rule

In a single-destination invocation, OpenSSH semantics win unconditionally. bssh extensions remain reachable through their long flags. The pdsh single-letter meanings survive only under --pdsh-compat or when bssh is invoked as pdsh through argv[0].

src/cli/mode_detection_tests.rs already carries mode-detection logic, so the dispatch point exists. What changes is which table of short flags that dispatch selects.

Scope

  • Reassign all seven letters to their OpenSSH meanings in single-destination mode: -N no remote command, -f background after authentication, -C compression, -A agent forwarding, -S ControlPath, -k disable GSSAPI credential forwarding, -b bind_address.
  • Keep every affected bssh feature reachable by long flag: --no-prefix, --filter, --cluster, --use-agent, --sudo-password, --fail-fast, --batch.
  • Keep the pdsh short forms working under --pdsh-compat and under the pdsh argv[0] symlink, since that mode has its own compatibility contract and its users are not asking for ssh semantics.
  • Ship a deprecation cycle before the reassignment: in the last 2.x release, using one of these letters in single-destination mode prints a warning naming the letter, the meaning it will take in 3.0, and the long flag that preserves today's behavior.
  • Update README.md, docs/man/bssh.1 and every example in the tree, including the port-forwarding examples that currently omit -N because it does not work.
  • Write a migration note covering the exact rewrite for each letter.

Risk

This breaks existing scripts, and that cannot be avoided while the compatibility claim stands. The mitigation is the deprecation cycle plus the fact that README.md has advertised drop-in replacement status since before this work began, so the reassignment moves the tool toward its documented contract rather than away from it.

Acceptance criteria

  • All seven letters carry OpenSSH semantics in single-destination mode.
  • bssh -N -L 8080:example.com:80 user@host forwards and does not open a shell.
  • Every displaced feature is reachable by long flag, covered by tests.
  • --pdsh-compat and the pdsh argv[0] path retain the pdsh meanings, covered by tests.
  • The 2.x deprecation warning fires for each affected letter and names its replacement.
  • README.md, the man page and all examples are updated, and a migration note is published.

Part of #275

Metadata

Metadata

Assignees

No one assigned

    Labels

    impact:breakingBreaking change that requires migrationpriority:highHigh priority issuestatus:backlogIn the backlog, not yet readytype:breaking-changeBreaking change that requires migrationtype:bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions