jaap-jan e6673f0bf2 Fix the CI formatting gate, which was already failing
dotnet format --verify-no-changes exits 2 on main: the async-suffix naming
rule fires on every async test method. I reported this gate as clean when
finishing the sync engine and it was not.

Test names are documentation. Push_WithAStaleVersion_ReportsConflict says
what is asserted; adding Async says the same plus an implementation detail
nobody reading a failure report needs. The suffix convention exists so
callers can spot awaitables, and a test method has no callers -- so the
rule is switched off under tests/ rather than the names being changed.
2026-07-28 16:05:52 +02:00
2026-07-28 12:28:44 +02:00

DodoSSH

A self-hosted, team-oriented SSH client with an end-to-end encrypted vault.

Manage hosts, credentials and keys in a desktop app; sync them across your devices and share them with teammates through a server you run yourself. The server stores ciphertext and never holds a key — the operator cannot read the credentials it stores.

Status: early development. See the milestone plan for what exists today.

Why

Teams either scatter SSH credentials across individual ~/.ssh directories with no sharing story, or pay per-seat for a hosted product that holds their infrastructure credentials. DodoSSH keeps the convenience of a synced, shareable vault while remaining self-hostable and zero-knowledge.

Architecture

Component Choice
Backend ASP.NET Core on .NET 10, PostgreSQL + EF Core
Client Avalonia (C#) for Windows/Linux/macOS; terminal pane is a WebView running xterm.js
Auth OIDC, provider-agnostic (Entra ID, Keycloak, Auth0, Authentik)
Vault End-to-end encrypted; X25519 + Ed25519 + XChaCha20-Poly1305, Argon2id unlock
Connections Client-direct SSH by default, with an optional raw-TCP server relay

Two consequences worth knowing before you read further:

  • Revocation is not retroactive. A removed member keeps what they already downloaded. The real remediation is rotating the SSH credential, so offboarding is built around a rotation checklist rather than a button that implies more than it delivers.
  • No session recording in relay mode. The relay forwards SSH ciphertext, so it cannot see commands. That is the cost of the relay not being able to read your traffic.

The reasoning behind each major decision is recorded in docs/adr/, starting with the E2EE trust model.

Repository layout

src/
  DodoSSH.Contracts       DTOs shared with the client — the real API contract
  DodoSSH.Crypto          DSH1 envelope, AAD derivation, key wrapping
  DodoSSH.Domain          entities and invariants, no EF
  DodoSSH.Infrastructure  DbContext, configurations, migrations
  DodoSSH.Api             the host
tests/                    one test project per source project
docs/adr/                 architecture decision records

Building

Requires the .NET SDK pinned in global.json (10.0.x).

dotnet build DodoSSH.slnx
dotnet test DodoSSH.slnx

Run the API locally:

dotnet run --project src/DodoSSH.Api

It listens on http://localhost:5233, serving /healthz/live, /healthz/ready and — in Development — /openapi/v1.json.

Conventions the build enforces

  • Warnings are errors. dotnet format --verify-no-changes gates CI.
  • Package versions are centralised in Directory.Packages.props; packages.lock.json is committed and CI restores in locked mode.
  • BannedSymbols.txt bans DateTime.UtcNow (use TimeProvider), Guid.NewGuid (use CreateVersion7), sync-over-async, MD5/SHA1 and PBKDF2.
  • Public members of DodoSSH.Contracts must be declared in PublicAPI.Unshipped.txt, so a contract change is a build error rather than a client-side surprise.

Milestones

  • M0 — foundation. Repo structure, build conventions, CI, ADRs. Done.
  • M1 — vertical slice. OIDC login → enroll → create a host → open a shell. Gated on freezing DodoSSH.Contracts and the crypto AAD, plus two client spikes (Linux WebView, SSH.NET window-change).
  • M2 — full personal vault, robust sync, relay.
  • M3 — teams, sharing, ACLs.
  • M4 — hardening and ops, packaging, self-hosting guide.
  • M5 — multi-provider OIDC, key rotation, per-item content keys.

Licence

Not yet chosen.

S
Description
No description provided
Readme MIT
8.7 MiB
Languages
C# 98%
PowerShell 0.7%
Shell 0.5%
JavaScript 0.5%
Dockerfile 0.2%