Restructure into src/tests and add build foundation (M0)

Moves the scaffold to src/DodoSSH.Api and establishes the repo conventions the rest
of the milestones build on.

Structure:
- src/{Contracts,Crypto,Domain,Infrastructure,Api}, tests/{Contracts,Crypto,Domain}.Tests
- DodoSSH.slnx rewritten with src/ and tests/ solution folders

Build:
- Directory.Build.props centralises TFM, nullable, deterministic builds and
  TreatWarningsAsErrors; Directory.Packages.props pins every version centrally
- packages.lock.json committed so CI restores in locked mode
- NuGet.config clears machine-level sources, which both fixes NU1507 under central
  package management and makes restore reproducible off this machine
- Microsoft.OpenApi pinned to 2.11.0: ASP.NET Core 10.0.10 resolves 2.0.0, which is
  covered by GHSA-v5pm-xwqc-g5wc (high, patched in 2.7.5)

Analyzers:
- AnalysisLevel is Recommended, not All. With warnings-as-errors, All turns opinionated
  naming rules into build breaks and trains people to blanket-suppress.
- BannedSymbols.txt bans DateTime.UtcNow (TimeProvider), Guid.NewGuid (CreateVersion7),
  sync-over-async, MD5/SHA1, PBKDF2 and SecureString
- CA1711/CA1724 disabled: both are .NET Framework CAS-era naming rules
- PublicApiAnalyzers on Contracts only, since that assembly is the client's real contract

API:
- weather-forecast template removed
- UseHttpsRedirection removed; TLS terminates at the reverse proxy and redirecting
  behind one causes loops
- /healthz/{live,ready,startup}. Liveness deliberately checks no dependencies so a
  transient database outage cannot restart the container and kill live SSH sessions.

Notes:
- No coverage collector yet. Microsoft.Testing.Extensions.CodeCoverage pulls an MTP 1.x
  MSBuild extension that throws TypeLoadException against the MTP 2.3.x xunit.v3 brings.
  Coverage gates are an M3 concern; revisit with an MTP 2.x-aligned version then.

Verified: dotnet build (0 warnings), 17 tests pass, format check clean, API serves
health and OpenAPI endpoints.
This commit is contained in:
2026-07-28 12:25:34 +02:00
parent 1138291d79
commit 3a81f3c90b
43 changed files with 1714 additions and 62 deletions
+51
View File
@@ -0,0 +1,51 @@
<Project>
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<PropertyGroup Label="Quality gates">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<!--
Recommended, not All. With TreatWarningsAsErrors on, latest-All turns opinionated
naming rules (CA1711 reserved suffixes, CA1724 namespace collisions) into build
breaks, which trains people to reach for blanket suppressions and devalues the
analyzers that catch real defects. Correctness and security rules we specifically
want beyond Recommended are raised individually in .editorconfig.
-->
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<AnalysisMode>Recommended</AnalysisMode>
<!-- The whole product is UTC-only and container-hosted; no tzdata, no culture-sensitive
formatting. Set here rather than per-project so it cannot drift. -->
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<PropertyGroup Label="Reproducible builds">
<Deterministic>true</Deterministic>
<ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
<!-- packages.lock.json is committed; CI restores in locked mode. -->
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>
<PropertyGroup Label="Assembly metadata">
<Company>DodoTech</Company>
<Product>DodoSSH</Product>
<NeutralLanguage>en</NeutralLanguage>
</PropertyGroup>
<ItemGroup Label="Analyzers">
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" PrivateAssets="all" />
<PackageReference Include="Meziantou.Analyzer" PrivateAssets="all" />
</ItemGroup>
<ItemGroup Label="Banned API list">
<AdditionalFiles Include="$(MSBuildThisFileDirectory)BannedSymbols.txt" Visible="false" />
</ItemGroup>
</Project>