feat(ssh_config): wire the parsed-but-unused ssh_config keywords
- Dominant language
- Rust
- Stars
- 65
- Forks
- 7
- Avg merge
- 1h 30m
- Merged PRs (30d)
- 25
Description
Part of the OpenSSH drop-in compatibility epic.
## Problem
bssh's ssh_config parser accepts roughly 70 keywords, but the resolved host config is barely consumed. Of 81 fields on the config struct, only about 10 are read anywhere outside `src/ssh/ssh_config/`: hostname, user, port, identity files, StrictHostKeyChecking, ProxyJump, Compression, AddressFamily, ServerAliveInterval and ServerAliveCountMax.
Everything else is parsed, validated, merged, and discarded. A user writes a directive, bssh accepts it without complaint, and the behavior does not change. Two instances were severe enough to get their own issues (`UserKnownHostsFile` and `ProxyCommand`), but the pattern is the general case, not the exception.
The following fields are assigned by the resolver and never read: `add_keys_to_agent`, `batch_mode`, `bind_interface`, `ca_signature_algorithms`, `certificate_files`, `check_host_ip`, `clear_all_forwardings`, `connection_attempts`, `control_master`, `control_path`, `control_persist`, `dynamic_forward`, `enable_ssh_keysign`, `escape_char`, `exit_on_forward_failure`, `fingerprint_hash`, `fork_after_authentication`, `forward_agent`, `forward_x11`, `forward_x11_timeout`, `forward_x11_trusted`, `gateway_ports`, `global_known_hosts_file`, `gssapi_authentication`, `hash_known_hosts`, `host_key_algorithms`, `host_key_alias`, `hostbased_accepted_algorithms`, `hostbased_authentication`, `identities_only`, `identity_agent`, `ipqos`, `kex_algorithms`, `keyboard_interactive_authentication`, `known_hosts_command`, `local_command`, `local_forward`, `log_level`, `macs`, `no_host_authentication_for_localhost`, `number_of_password_prompts`, `password_authentication`, `permit_local_command`, `permit_remote_open`, `preferred_authentications`, `proxy_command`, `proxy_use_fdpass`, `pubkey_accepted_algorithms`, `pubkey_authentication`, `rekey_limit`, `remote_command`, `remote_forward`, `request_tty`, `required_rsa_size`, `send_env`, `session_type`, `stdin_null`, `syslog_facility`, `tcp_keep_alive`, `update_host_keys`, `user_known_hosts_file`, `verify_host_key_dns`, `visual_host_key`.
## Scope
This is a tracking issue. Wire the keywords in the order the regression suite exercises them, and split out any individual keyword that turns out to be large enough to deserve its own issue.
First wave, each directly blocking a named regress test:
- [ ] `SendEnv` and `SetEnv` (`envpass`)
- [ ] `LocalCommand` and `PermitLocalCommand` (`localcommand`)
- [ ] `RequestTTY` and `SessionType` (`ssh-tty`, `match-subsystem`)
- [ ] `RemoteCommand` (`percent`, `host-expand`)
- [ ] `LocalForward`, `RemoteForward`, `DynamicForward`, `ClearAllForwardings`, `ExitOnForwardFailure` (`forwarding`, `dynamic-forward`, `forward-control`)
- [ ] `Ciphers`, `MACs`, `KexAlgorithms`, `HostKeyAlgorithms`, `PubkeyAcceptedAlgorithms` (`try-ciphers`, `kextype`, `keytype`, `limit-keytype`, `integrity`)
- [ ] `IdentitiesOnly`, `CertificateFile`, `PreferredAuthentications`, `PubkeyAuthentication`, `PasswordAuthentication`, `NumberOfPasswordPrompts`, `BatchMode` (`multipubkey`, `cert-file`, `cert-userkey`, `key-options`)
- [ ] `RekeyLimit` (`rekey`)
- [ ] `CheckHostIP`, `UpdateHostKeys`, `HashKnownHosts`, `KnownHostsCommand`, `VerifyHostKeyDNS` (`knownhosts`, `knownhosts-command`, `hostkey-rotate`)
- [ ] `ConnectionAttempts`, `TCPKeepAlive`, `IPQoS`, `BindAddress`, `BindInterface`
Second wave, no regress coverage but user-facing: `AddKeysToAgent`, `ForwardAgent`, `IdentityAgent`, `EscapeChar`, `FingerprintHash`, `VisualHostKey`, `LogLevel`, `SyslogFacility`, `StdinNull`, `ForkAfterAuthentication`, `RequiredRSASize`, `GatewayPorts`, `PermitRemoteOpen`.
Out of scope for this epic and to be rejected as unimplemented rather than silently accepted: `GSSAPIAuthentication`, `HostbasedAuthentication`, `HostbasedAcceptedAlgorithms`, `EnableSSHKeysign`, `ForwardX11`, `ForwardX11Trusted`, `ForwardX11Timeout`.
## Implementation decomposition
- [x] #295 — registry, provenance, generic `-o`, algorithms, retries, and TCP keepalive. Depends on #279 and #280.
- [ ] #296 — authentication policy and user certificates. Depends on #295.
- [ ] #297 — environment, local/remote command, TTY, and session policy. Depends on #295.
- [ ] #298 — live forwarding directives. Depends on #295 and #297.
- [ ] #299 — known-host policy, DNS checks, and secure key rotation. Depends on #295.
- [ ] #300 — source binding and IPQoS. Depends on #295 and #297.
- [ ] #301 — RekeyLimit transport enforcement. Depends on #295.
Keep this tracker open until all seven implementation issues are merged, every first-wave directive has a behavior test, the registry invariant passes, and the named regress set is rerun against the integrated main branch.
## Structural requirement
Whatever the outcome per keyword, the silently-parsed state must stop existing. Every keyword the parser accepts must either change behavior at runtime or produce a warning that names it as unimplemented. Add a test that walks the accepted-keyword table and asserts each entry falls into one of those two buckets, so a future keyword cannot be added in the parse-and-discard shape.
## Acceptance criteria
- [ ] Each first-wave keyword is consumed at runtime and covered by a test asserting the behavior changes.
- [ ] Unimplemented keywords warn once, naming the keyword and the line, instead of being discarded.
- [ ] The accepted-keyword table has no entry that is neither consumed nor declared unimplemented, enforced by a test.
- [ ] The regress tests named against the first wave pass in the harness.
Part of #275.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in src/ssh/ssh_config/ and inspect the accepted-keyword table, then run the named regress tests to establish the current failures. Use the dependency order in issues #296–#301 to choose a narrower implementation area. Done means first-wave directives are consumed and behavior-tested, while other accepted keywords warn explicitly and the registry invariant passes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cli, networking
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100