Files
DodoSSH/tests/DodoSSH.Crypto.Tests/CryptoSpecTests.cs
T
jaap-jan 3a81f3c90b 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.
2026-07-28 12:25:34 +02:00

46 lines
1.5 KiB
C#

using DodoSSH.Crypto;
namespace DodoSSH.Crypto.Tests;
/// <summary>
/// Pins the specification constants that are written into stored data.
/// </summary>
/// <remarks>
/// These are not busywork. The envelope magic and AAD version are persisted in every
/// ciphertext row, and only clients can re-encrypt: if one of these changes without a
/// deliberate migration path, existing vaults stop decrypting and the server cannot help.
/// </remarks>
public sealed class CryptoSpecTests
{
[Fact]
public void EnvelopeMagic_IsStable()
{
CryptoSpec.EnvelopeMagic.ShouldBe("DSH1");
}
[Fact]
public void CurrentAadVersion_IsStable()
{
// Bumping this requires a lazy re-encrypt-on-write path in the client first.
CryptoSpec.CurrentAadVersion.ShouldBe((short)1);
}
[Theory]
[InlineData(CryptoSpec.AlgorithmId.XChaCha20Poly1305, 1)]
[InlineData(CryptoSpec.AlgorithmId.Aes256Gcm, 2)]
[InlineData(CryptoSpec.AlgorithmId.SealToX25519, 3)]
public void AlgorithmId_HasStableWireValue(CryptoSpec.AlgorithmId algorithm, int expected)
{
((int)algorithm).ShouldBe(expected);
}
[Fact]
public void AlgorithmId_4_IsReservedForHybridPostQuantumSeal()
{
// Reserved for X25519 + ML-KEM-768. Claimed now so the identifier cannot be
// reused: store-now-decrypt-later is a real threat for long-lived SSH keys.
// AlgorithmId is byte-backed, matching the single alg_id byte in the envelope.
Enum.IsDefined(typeof(CryptoSpec.AlgorithmId), (byte)4).ShouldBeFalse();
}
}