From 483ae1fed9404d5cb8b7eff454db9017486f91bb Mon Sep 17 00:00:00 2001 From: Laurens Bezemer | DodoTech Date: Mon, 31 Aug 2026 16:35:14 +0200 Subject: [PATCH] Stop three notes in this repository claiming things that are not so MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A scan of the working tree and all 335 commits for anything that should not be public found no leaked secret. What it did find was three places where a reader is told something the repository does not back up, and in a public repository a confident wrong note is worse than silence: nobody goes and checks a sentence that sounds settled. The ignore list stopped at *.pfx, *.p12 and *.snk, so a keystore was not covered at all. The one that matters is the release keystore ADR 0011 rule 1 keeps off runners — drop it in the tree while cutting a release and nothing would have said a word. *.keystore and *.jks now, with build/nightly.keystore negated: an ignore rule cannot untrack a tracked file, so the negation changes no behaviour and is there so the next reader does not take the committed one for an accident. ADR 0014 is cited beside it, because "a signing key is committed here on purpose" is a claim that needs its argument within reach. Also gone from that list: a negation for deploy/.env.example, which has never existed in any commit. RelayOptions.AllowPrivateNetworks said loopback, link-local and cloud metadata ranges "are denied unconditionally and are not configurable" — present tense, in the voice of a control that exists. Nothing reads the setting. There is no relay endpoint and no dialler; the relay is ADR 0004 and a contract type. So the sentence most likely to be read by somebody auditing this repository's SSRF posture was describing code nobody has written. It now says that outright, and hands the obligation to whoever builds the dialler with ADR 0004 §3 named in full, including the IPv4-mapped IPv6 re-check, which is the clause a fresh implementation is likeliest to miss. The flag governs RFC1918 and never that list, which was the other half the old wording ran together. docker-compose.dev.yml pointed at deploy/docker-compose.yml as "the production stack". That file has never existed here either. Says what does ship — the image the CI image job builds and pushes — and puts a compose file to run it where it belongs, in M4's self-hosting guide. Comments and an ignore list only; no behaviour moves. The API builds clean, and the two tests that mention the dev compose file read its Postgres version, which is untouched. Left alone deliberately: release-android.ps1 and release-windows.ps1 pass the keystore password and the forge token as arguments to a child process, where another process on the machine can read them off the command line. That is a real if small hole and a code change rather than a comment — the vpk half needs somebody to find out whether it takes the token from the environment first. Co-Authored-By: Claude Opus 5 --- .gitignore | 9 ++++++++- deploy/docker-compose.dev.yml | 7 ++++++- src/DodoSSH.Api/Setup/DodoOptions.cs | 14 ++++++++++++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 5a3161f..7b9bd8d 100644 --- a/.gitignore +++ b/.gitignore @@ -87,9 +87,16 @@ Releases/ *.pfx *.p12 *.snk +# Signing keystores, with one exception that is tracked deliberately. build/nightly.keystore is +# committed in the open on purpose — see ADR 0014 for why a key everybody holds is what makes the +# nightly channel safe to run in CI — and a file already tracked is unaffected by an ignore rule +# anyway. The negation is here so that reading this list does not suggest the tracked one is an +# oversight. The *release* keystore is a real secret under ADR 0011 rule 1 and must never land here. +*.keystore +*.jks +!build/nightly.keystore appsettings.Local.json appsettings.*.Local.json .env .env.* -!deploy/.env.example secrets/ diff --git a/deploy/docker-compose.dev.yml b/deploy/docker-compose.dev.yml index d799eed..73910f3 100644 --- a/deploy/docker-compose.dev.yml +++ b/deploy/docker-compose.dev.yml @@ -1,7 +1,12 @@ # Development dependencies only: PostgreSQL and Keycloak. # # The API itself runs from the IDE or `dotnet run`, so the inner loop stays fast while the -# schema is still churning. The production stack is deploy/docker-compose.yml. +# schema is still churning. +# +# There is no production compose file in this repository. This one said there was, naming a +# deploy/docker-compose.yml that has never existed in any commit. What ships instead is the +# container image the CI image job builds and pushes; a compose file to run it belongs to the +# self-hosting guide in M4, and until that exists the honest thing to say is that it does not. # # docker compose -f deploy/docker-compose.dev.yml up -d # dotnet run --project src/DodoSSH.Api diff --git a/src/DodoSSH.Api/Setup/DodoOptions.cs b/src/DodoSSH.Api/Setup/DodoOptions.cs index 6fb14e4..100326a 100644 --- a/src/DodoSSH.Api/Setup/DodoOptions.cs +++ b/src/DodoSSH.Api/Setup/DodoOptions.cs @@ -115,10 +115,20 @@ public sealed class RelayOptions /// Whether RFC1918 and other private ranges may be dialled. /// /// + /// /// Defaults to true, unlike a typical SSRF allow-list, because reaching private /// infrastructure is the entire purpose of a self-hosted SSH tool. The control that matters is - /// the ACL: only hosts in a vault the caller holds Connect on can be dialled at all. Loopback, - /// link-local and cloud metadata ranges are denied unconditionally and are not configurable. + /// the ACL: only hosts in a vault the caller holds Connect on can be dialled at all. + /// + /// + /// Nothing reads this setting yet, and that is the point of saying so here. The relay is + /// an ADR and a contract; there is no endpoint and no dialler. This option exists so the shape + /// is settled before the code is, which makes it exactly the kind of comment that gets read as a + /// description of an implemented control. It is not one. Whoever builds the dialler owes ADR 0004 + /// §3 in full — loopback, link-local, 0.0.0.0/8, multicast and the cloud metadata addresses + /// denied with no configuration escape, and IPv4-mapped IPv6 normalised and re-checked — and this + /// flag governs RFC1918 only, never that list. + /// /// public bool AllowPrivateNetworks { get; set; } = true;