Skip to content

M17.1: anvil_ssh::algorithms module — denylist + +/-/^ parser + catalogue#25

Merged
UnbreakableMJ merged 1 commit into
mainfrom
feature/m17-1-algorithms-module
May 4, 2026
Merged

M17.1: anvil_ssh::algorithms module — denylist + +/-/^ parser + catalogue#25
UnbreakableMJ merged 1 commit into
mainfrom
feature/m17-1-algorithms-module

Conversation

@UnbreakableMJ

Copy link
Copy Markdown
Contributor

Summary

First slice of M17 (PRD §5.8.6 — algorithm overrides). Adds the library-side scaffold needed for FR-76 / FR-77 / FR-78 / FR-79 — the M17.2 PR plumbs this into AnvilConfig + build_russh_config and the M17.4 PR wires the Gitway CLI flags + list-algorithms subcommand on top.

New anvil_ssh::algorithms module

  • DENYLIST + is_denylisted / apply_denylist (FR-78) — permanent block on DSA, 3DES, Arcfour variants, hmac-sha1-96, SSH-1. Override mentions surface a hard error with a tips-thinking hint pointing at gitway list-algorithms and an external ssh -W workaround.
  • AlgCategory { Kex, Cipher, Mac, HostKey } with .label().
  • apply_overrides(category, base, override_str) (FR-77) — OpenSSH +algo / -algo / ^algo / algo,algo parser. Trims whitespace, dedupes appends case-insensitively, preserves order on front-loads (reorder-not-add semantics), denylist-filters after every transformation.
  • anvil_default_kex / _ciphers / _macs / _host_keys — curated default base for +/-/^ overrides.
  • Catalogue { kex, cipher, mac, host_key } of AlgEntry { name, is_default, denylisted } (FR-79) — sourced from russh's named constants for gitway list-algorithms.

Tests (23 unit tests)

Denylist case-insensitivity, prefix-matrix coverage, dedup, silent-skip on absent removes, denylisted-token rejection, error-hint shape, whitespace trim, empty-token drop, catalogue invariants (≥1 default per category, default+denylisted disjoint, ssh-dss tagged), category-label stability.

Public API: pure additive. Version bump to 0.8.0 lands in M17.3.

Test plan

  • cargo fmt --all -- --check
  • cargo clippy --all-targets --all-features --locked -- -D warnings
  • cargo test --lib algorithms:: — 23 passed, 0 failed
  • CI matrix on this PR (Linux/macOS/Windows + MSRV 1.88)

🤖 Generated with Claude Code

… FR-78, FR-79 lib side)

Adds the library-side scaffold M17 needs to honour KexAlgorithms /
Ciphers / MACs / HostKeyAlgorithms from `~/.ssh/config` (FR-76),
parse OpenSSH-format CLI overrides (FR-77), enforce the permanent
denylist (FR-78), and surface the algorithm catalogue for
`gitway list-algorithms` (FR-79).

src/algorithms.rs (new, ~470 lines + ~250 lines of tests):

- pub const DENYLIST: &[&str] — DSA, 3DES, Arcfour variants,
  hmac-sha1-96, ssh-1.0.  Per FR-78 the list is permanent: an
  override referencing any entry is rejected with a
  tips-thinking hint pointing at `gitway list-algorithms` and an
  external `ssh -W` workaround.
- pub fn is_denylisted(alg) / apply_denylist(list) — case-insensitive
  ASCII matching helpers.
- pub enum AlgCategory { Kex, Cipher, Mac, HostKey } with .label().
- pub fn apply_overrides(category, base, override_str) — the
  OpenSSH-format `+algo` (append) / `-algo` (remove) / `^algo`
  (front-load) / `algo,algo` (replace) parser.  Trims whitespace,
  drops empty tokens, deduplicates appends case-insensitively,
  preserves ordering on front-loads, silently skips removes for
  absent entries (matches OpenSSH behaviour).  Calls apply_denylist
  after every transformation.  Errors hard on a denylisted token
  in any prefix form.
- pub fn anvil_default_kex / _ciphers / _macs / _host_keys — the
  curated default lists used as the base for `+/-/^` overrides.
  Kex matches what build_russh_config currently hardcodes;
  ciphers/macs/host-keys are the safe set Gitway will negotiate
  once M17.2 plumbs them through.
- pub struct AlgEntry { name, is_default, denylisted } and
  pub struct Catalogue { kex, cipher, mac, host_key } with
  pub fn all_supported() — enumerates every name russh advertises
  (sourced from russh::{kex,cipher,mac}::* constants) and tags
  each with the two flags.

src/lib.rs:
- pub mod algorithms;

Public API: pure additive.  Version bump to 0.8.0 lands in M17.3.

23 unit tests covering: denylist case-insensitivity, Arcfour
variant matching, safe-algorithm pass-through, denylist-preserving
filter, all five prefix branches (none/+/-/^/empty), case-insensitive
dedup on append, silent skip on remove of absent, OpenSSH front-load
semantics (reorder-not-add), hard error on denylisted token in
override (in both replace and append forms), error hint mentioning
`gitway list-algorithms`, empty-token drop, whitespace trim,
catalogue completeness (≥1 default per category, denylisted entries
tagged, default+denylisted disjoint), curated-defaults exclude
denylist, host-key default excludes ssh-dss / includes ssh-ed25519,
category labels stable.

Plan: M17.1 of anvil-gitway-milestone-plan.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@UnbreakableMJ UnbreakableMJ merged commit d47e952 into main May 4, 2026
5 checks passed
@UnbreakableMJ UnbreakableMJ deleted the feature/m17-1-algorithms-module branch May 4, 2026 18:56
UnbreakableMJ added a commit that referenced this pull request May 4, 2026
…errides) (#27)

Final Anvil-side slice of M17.  Bumps anvil-ssh from 0.7.0 to 0.8.0
to publish the M17.1 + M17.2 work as a single crates.io release.
The Gitway-side CLI flags + list-algorithms subcommand (M17.4 +
M17.5) land against this 0.8.0; the M17.X PRD doc PR closes the
milestone with Gitway v1.0.0-rc.8.

Cargo.toml:
- version "0.7.0" -> "0.8.0"

Cargo.lock:
- regenerated locally; reflects the 0.8.0 version.

CHANGELOG.md:
- 0.8.0 entry covering the new anvil_ssh::algorithms module, the
  four new AnvilConfig fields + builder setters, the
  apply_ssh_config algorithm-directive consumption, the
  build_russh_config signature change, and the FR-66 / CAT_KEX
  tracing event for offered algorithm preferences.

Stacked after PRs #25 (M17.1, merged) and #26 (M17.2, merged).

Plan: M17.3 of anvil-gitway-milestone-plan.md.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant