Skip to content

Commit a23b39d

Browse files
chore(release): anvil-ssh 1.0.0 — first stable release (#31)
First stable release. No API change from 0.9.0; this release is a stabilization signal under SemVer. CHANGELOG declares the public API stable: patch bumps add no symbols, minor bumps add only, major bumps coordinate with downstream consumers (primarily Steelbore/Gitway). The legacy GitwaySession / GitwayConfig / GitwayError #[deprecated] aliases stay through the entire 1.x line. This is a deliberate softening of the original AGENTS.md roadmap (which had proposed removing them at 1.0): the corresponding gitway-lib shim re-exports anvil_ssh::* glob-style and is preserved through Gitway 1.x per Gitway's docs/migration-from-v0.9.md; removing the upstream aliases now would silently break that shim. Removal is scheduled for 2.0. README rewritten for v1.0: - Updated Status block (1.0.0 stable, MSRV 1.88) - Updated Use block (anvil-ssh = "1.0", deprecation timeline) - New v1.0 feature matrix - "What this is NOT" section clarifying scope - Refreshed module table with M11.5-M19 modules (cert_authority, ssh_config, proxy, algorithms, retry, log) - Security section linking to Gitway's threat model + the RUSTSEC-2023-0071 residual-risk note AGENTS.md type-rename roadmap revised to defer Gitway* alias removal to 2.0; SemVer commitment block added. Local verification: - cargo build --release: 2m21s, clean - cargo clippy --all-targets -- -D warnings: clean (47s) - cargo fmt --check: clean - cargo test: 292 passed, 0 failed, 7 ignored (require GITWAY_INTEGRATION_TESTS=1) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent b8f55c3 commit a23b39d

5 files changed

Lines changed: 158 additions & 13 deletions

File tree

AGENTS.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,19 @@ Pure-Rust SSH stack for Git tooling: transport, keys, signing, agent. Foundatio
5050

5151
## Type rename roadmap
5252

53-
- `v0.1.x` — types carried over from the source crate as `GitwaySession` / `GitwayConfig` / `GitwayError` to keep the lift-and-shift extraction zero-rename. Downstream churn limited to crate-name change.
54-
- `v0.2.0` (current) — types renamed to `AnvilSession` / `AnvilConfig` / `AnvilError`. Legacy `Gitway*` names retained as `#[deprecated]` re-exports for one major version.
55-
- `v1.0.0` — stabilization; cut concurrently with Gitway 1.0.0. Deprecated `Gitway*` aliases removed.
53+
- `v0.1.x` — types carried over from the source crate as `GitwaySession` / `GitwayConfig` / `GitwayError` to keep the lift-and-shift extraction zero-rename.
54+
- `v0.2.0` — types renamed to `AnvilSession` / `AnvilConfig` / `AnvilError`. Legacy `Gitway*` names retained as `#[deprecated]` re-exports.
55+
- `v1.0.0` (current) — stabilization, cut concurrently with Gitway 1.0.0. Deprecated `Gitway*` aliases **kept** through the 1.x line. This is a deliberate softening of the original roadmap (which had proposed removing them at 1.0): the corresponding `gitway-lib` shim re-exports `anvil_ssh::*` glob-style and is preserved through Gitway 1.x per Gitway's `docs/migration-from-v0.9.md`. Removing the upstream aliases at 1.0 would silently break that shim.
56+
- `v2.0.0` (planned) — deprecated `Gitway*` aliases removed.
5657

5758
## Versioning
5859

59-
SemVer. Pre-1.0 minor bumps may break public API; patch bumps are bug fixes only. See `CHANGELOG.md` for the cumulative record.
60+
SemVer. As of v1.0.0, the public API is **frozen under SemVer**:
61+
62+
- **Patch bumps** (`1.0.x`) are bug fixes only — no API additions.
63+
- **Minor bumps** (`1.x.0`) may add new public symbols; existing
64+
ones never change shape or behavior.
65+
- **Major bumps** (`x.0.0`) are reserved for breaking changes and
66+
are coordinated with downstream consumers (primarily Gitway).
67+
68+
See `CHANGELOG.md` for the cumulative record.

CHANGELOG.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,86 @@
22

33
All notable changes to Anvil are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow [SemVer](https://semver.org/).
44

5+
## [1.0.0] — TBD
6+
7+
The first stable release of `anvil-ssh`. This release declares the
8+
public API **stable under SemVer**: every `pub` symbol that's
9+
exposed today is supported through the 1.x line.
10+
11+
### Public API stability commitment
12+
13+
From 1.0 onward:
14+
15+
- **Patch bumps** (`1.0.x`) are bug fixes only — no API additions.
16+
- **Minor bumps** (`1.x.0`) may add new public symbols; existing
17+
ones never change shape or behavior.
18+
- **Major bumps** (`x.0.0`) are reserved for breaking changes and
19+
are coordinated with downstream consumers — primarily
20+
[Steelbore/Gitway](https://github.com/Steelbore/Gitway).
21+
22+
### Deprecation timeline (revised at 1.0)
23+
24+
The legacy `GitwaySession` / `GitwayConfig` / `GitwayError` aliases
25+
that were marked `#[deprecated]` in 0.2.0 **remain in 1.x**. This
26+
is a deliberate softening of the original `AGENTS.md` roadmap (which
27+
proposed removing them at 1.0): the corresponding
28+
[`gitway-lib` shim](https://github.com/Steelbore/Gitway/blob/main/gitway-lib/src/lib.rs)
29+
re-exports `anvil_ssh::*` through the legacy `gitway_lib::*` path
30+
and is preserved through Gitway's 1.x line per the
31+
[Gitway migration doc](https://github.com/Steelbore/Gitway/blob/main/docs/migration-from-v0.9.md);
32+
removing the upstream aliases now would silently break that shim.
33+
Removal is now scheduled for 2.0.0.
34+
35+
### Changed
36+
37+
- **Version bump** 0.9.0 → 1.0.0. No API changes from 0.9.0; this
38+
release is a stabilization signal.
39+
40+
### Added
41+
42+
Nothing new in 1.0.0 itself. Cumulative additions since 0.1.0 are
43+
documented in the per-version sections below; the M11.5 → M19
44+
work landed in 0.1 through 0.9.
45+
46+
### Removed
47+
48+
Nothing. The deprecated `Gitway*` aliases stay through the 1.x
49+
line (see Deprecation timeline).
50+
51+
### Out of scope (deferred to 1.x or 2.0)
52+
53+
Tracked as work to land in subsequent releases:
54+
55+
- **FR-61, FR-62, FR-63 — live `@cert-authority` validation
56+
during KEX.** Blocked on russh upstream cert-host-key
57+
support. Will land in a 1.x minor when russh exposes server
58+
certificates to `check_server_key`.
59+
- **FIDO2 / `sk-ssh-*` hardware-backed keys** (Gitway PRD §5.8.5,
60+
M16). Vendor fragmentation across YubiKey, SoloKeys, OnlyKey
61+
needs a hardware-test matrix; deferred to a 1.x minor.
62+
- **Full `Match` block semantics in `ssh_config`** (Gitway PRD
63+
§12 Q1). Parser support landed in M12; eval semantics deferred
64+
to a 1.x minor.
65+
66+
### Known residual risks
67+
68+
- **RUSTSEC-2023-0071 (Marvin Attack on the `rsa` crate).** No
69+
patch available upstream
70+
([RustCrypto/RSA #626](https://github.com/RustCrypto/RSA/issues/626)).
71+
Documented + accepted with rationale in
72+
[Gitway's `docs/security.md`](https://github.com/Steelbore/Gitway/blob/main/docs/security.md):
73+
the `rsa` crate is only on the local keygen + SSHSIG paths;
74+
transport crypto is `aws-lc-rs` (constant-time); SSH auth uses
75+
Ed25519 by default. We will bump as soon as upstream ships a
76+
patched release.
77+
78+
### Verification
79+
80+
- `cargo build --release` clean
81+
- `cargo test` — 207+ unit + integration tests pass
82+
- `cargo clippy --all-targets -- -D warnings` clean
83+
- `cargo fmt --check` clean
84+
585
## [0.9.0] — 2026-05-04
686

787
### Added

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# SPDX-License-Identifier: GPL-3.0-or-later
22
[package]
33
name = "anvil-ssh"
4-
version = "0.9.0"
4+
version = "1.0.0"
55
edition = "2021"
66
license = "GPL-3.0-or-later"
77
authors = ["Mohamed Hammad <MJ@S3cure.me>"]

README.md

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@ Anvil is the foundation library extracted from [Steelbore/Gitway](https://github
66

77
## Status
88

9-
`v0.1.0` — initial cold-start extraction from Steelbore/Gitway @ `28abee6`. Pre-1.0; the public type names will rename in `0.2.0` (see [CHANGELOG](CHANGELOG.md)). Full v1.0 scope and roadmap live in the [Gitway PRD](https://github.com/steelbore/gitway/blob/main/Gitway-PRD-v1.0.md).
9+
**`v1.0.0`** — first stable release. Public API frozen under SemVer
10+
through the 1.x line. Full release notes in [CHANGELOG.md](CHANGELOG.md);
11+
roadmap context in the [Gitway PRD](https://github.com/Steelbore/Gitway/blob/main/Gitway-PRD-v1.0.md).
12+
13+
**MSRV:** Rust 1.88.
1014

1115
## Use
1216

1317
```toml
1418
[dependencies]
15-
anvil-ssh = "0.1"
19+
anvil-ssh = "1.0"
1620
```
1721

1822
```rust,no_run
@@ -29,22 +33,66 @@ async fn main() -> Result<(), anvil_ssh::AnvilError> {
2933
}
3034
```
3135

32-
The flat re-exports `AnvilSession` / `AnvilConfig` / `AnvilError` were renamed in `0.2.0` from the legacy `GitwaySession` / `GitwayConfig` / `GitwayError` (which were carried over from the source crate to keep the 0.1.0 extraction zero-rename). The legacy names remain available as `#[deprecated]` re-exports for one major version per [Gitway PRD §7.4](https://github.com/steelbore/gitway/blob/main/Gitway-PRD-v1.0.md); they will be removed in `1.0.0`. Migration is mechanical — `s/Gitway/Anvil/g` in your `use anvil_ssh::*;` imports.
36+
The flat re-exports `AnvilSession` / `AnvilConfig` / `AnvilError`
37+
were renamed in `0.2.0` from the legacy `GitwaySession` /
38+
`GitwayConfig` / `GitwayError`. The legacy names remain available
39+
as `#[deprecated]` re-exports through the entire 1.x line; removal
40+
is scheduled for 2.0.0. Migration is mechanical — `s/Gitway/Anvil/g`
41+
in your `use anvil_ssh::*;` imports.
42+
43+
## Feature matrix (v1.0)
44+
45+
| Area | What's supported | What's deferred |
46+
| ---- | ---------------- | --------------- |
47+
| **Transport** | SSH-2 connect, exec channel, pinned host-key verification (SHA-256 fingerprints for GitHub, GitLab, Codeberg), `aws-lc-rs` crypto | None for v1.0 |
48+
| **`ssh_config(5)`** | Lexer/parser/resolver, `Include`, `Host`, `HostName`, `Port`, `User`, `IdentityFile`, `IdentityAgent`, `IdentitiesOnly`, `CertificateFile`, `StrictHostKeyChecking`, `UserKnownHostsFile`, `ProxyCommand` (incl. `=none` sentinel), `ProxyJump`, `KexAlgorithms`/`Ciphers`/`MACs`/`HostKeyAlgorithms`, `ConnectTimeout`, `ConnectionAttempts` | Full `Match` block semantics (parsed; never matches; deferred to 1.x minor) |
49+
| **Proxies** | `ProxyCommand` token expansion (`%h %p %r %n %%`); `ProxyJump` chains up to 8 hops; independent host-key verification at every hop | Per-hop retry semantics (single-attempt fallback for proxy paths) |
50+
| **`@cert-authority` host CA** | Parsing, surfacing in audit logs, `@revoked` blocklist with policy-overriding semantics | Live cert validation during KEX (FR-61/62/63 — blocked on russh upstream; will land in 1.x) |
51+
| **Connection retry** | Exponential backoff with jitter, fatal-vs-transient classifier, per-attempt timeout, max-retry-window, retry history accessor | HTTP 429/503 (no HTTP layer in transport path) |
52+
| **Algorithm overrides** | OpenSSH `+/-/^/replace` syntax, denylist (DSA / 3DES / RC4 / hmac-sha1-96 / SSH-1) | None for v1.0 |
53+
| **`known_hosts`** | Parse and write hashed (`HashKnownHosts yes`) entries via HMAC-SHA1; `@cert-authority`, direct, and `@revoked` lines; embedded fingerprint catalogue | None for v1.0 |
54+
| **Keys** | Ed25519 / ECDSA-P256/P384/P521 / RSA generation in OpenSSH format; passphrase encryption + change | FIDO2 / `sk-ssh-*` hardware-backed keys (deferred to 1.x; see Gitway PRD §5.8.5 / M16) |
55+
| **Signing** | SSHSIG produce / verify / `find-principals` / `check-novalidate`; `allowed_signers` file parser | None for v1.0 |
56+
| **Agent** | Cross-platform client (Unix domain socket on Unix; named pipe on Windows interoperable with `\\.\pipe\openssh-ssh-agent`); async daemon (Unix `setsid(2)` + Windows foreground modes) | Background-mode `gitway agent start` without `-D` is Unix-only; Windows requires foreground (`-D` plus a launcher) |
57+
| **Tracing** | Per-category targets (`CAT_KEX`, `CAT_AUTH`, `CAT_CHANNEL`, `CAT_CONFIG`, `CAT_RETRY`); `tracing_log` bridge for legacy `log::*!` callers; structured events at every host-key check, auth attempt, applied directive, and ProxyJump hop | None for v1.0 |
58+
59+
## What this is NOT
60+
61+
- **Not a general-purpose SSH library.** Anvil targets the SSH
62+
surface that Git needs — exec channels, key management, signing,
63+
agent. No PTY, no SFTP, no port forwarding, no SCP.
64+
- **Not a TLS or HTTP toolkit.** SSH only.
65+
- **Not a runtime.** Anvil exposes async APIs but doesn't install
66+
a tracing subscriber or pick an executor for you. Consumers
67+
(typically [Gitway](https://github.com/Steelbore/Gitway)) own the
68+
runtime/subscriber policy.
69+
- **Not a TOFU implementation.** The known-host fingerprints for
70+
GitHub, GitLab, and Codeberg are pinned at build time. Adding
71+
a new provider is a code change, reviewed and shipped in a
72+
minor release.
3373

3474
## Modules
3575

3676
| Module | Purpose |
3777
| --------------------- | ---------------------------------------------------------------- |
38-
| `session` | russh-backed SSH session lifecycle |
78+
| `session` | russh-backed SSH session lifecycle (connect, retry-wrapped) |
79+
| `config` | `AnvilConfig` builder; convenience constructors per provider |
80+
| `error` | `AnvilError` and the unified error taxonomy |
3981
| `auth` | Identity discovery (CLI flag → `~/.ssh` paths → SSH agent) |
40-
| `hostkey` | Pinned host fingerprints (GitHub, GitLab, Codeberg) |
82+
| `hostkey` | Pinned host fingerprints; `host_key_trust` audit-log API |
83+
| `cert_authority` | `@cert-authority` / `@revoked` parser + `HashedHost` (M19) |
84+
| `ssh_config` | OpenSSH `ssh_config(5)` lexer / parser / matcher / resolver |
85+
| `proxy` | `ProxyCommand` token expansion + `ProxyJump` chains |
86+
| `algorithms` | KEX/cipher/MAC/host-key catalogue + override syntax + denylist |
87+
| `retry` | `RetryPolicy` + classifier + jittered exponential-backoff loop |
4188
| `relay` | Bidirectional stdin/stdout/stderr relay over an exec channel |
4289
| `keygen` | Ed25519 / ECDSA / RSA keypair generation in OpenSSH format |
4390
| `sshsig` | SSHSIG sign / verify / `find-principals` / `check-novalidate` |
4491
| `allowed_signers` | Parser for git's `allowed_signers` file format |
45-
| `agent::client` | Blocking SSH agent client (`ssh-add` equivalent) |
46-
| `agent::daemon` | Async SSH agent server (`ssh-agent` equivalent) |
92+
| `agent::client` | Cross-platform SSH agent client (`ssh-add` equivalent) |
93+
| `agent::daemon` | SSH agent server (`ssh-agent` equivalent) |
4794
| `agent::askpass` | `$SSH_ASKPASS`-driven interactive confirmation |
95+
| `log` | Tracing-category constants + `install_log_bridge()` |
4896
| `diagnostic` | Single-line stderr failure diagnostic helper |
4997
| `time` | ISO 8601 timestamp helpers (no `chrono` / `time` crate dep) |
5098

@@ -68,6 +116,14 @@ cargo fmt --check
68116

69117
`perl` is required by `aws-lc-rs` for assembly pre-processing on every platform; `nasm` is also required on Windows MSVC.
70118

119+
## Security
120+
121+
See [Gitway's `docs/security.md`](https://github.com/Steelbore/Gitway/blob/main/docs/security.md) for the full threat model. TL;DR: Anvil defends against active network attackers (pinned fingerprints, algorithm denylist, `@revoked` enforcement) and memory-safety classes (`#![forbid(unsafe_code)]` everywhere). One known residual risk is documented:
122+
123+
- **RUSTSEC-2023-0071** — Marvin Attack on the `rsa` crate. No upstream patch yet; we use `rsa` only for local keygen + SSHSIG signing (transport crypto is `aws-lc-rs`, constant-time). The default key type is Ed25519, which is unaffected.
124+
125+
Disclosure policy: [Gitway's `SECURITY.md`](https://github.com/Steelbore/Gitway/blob/main/SECURITY.md).
126+
71127
## License
72128

73129
GPL-3.0-or-later. Copyright © 2026 Mohamed Hammad. See [LICENSE](LICENSE).

0 commit comments

Comments
 (0)