-
Notifications
You must be signed in to change notification settings - Fork 3
Project Handbook
Building each component, running the tests, the contribution rules and required checks, the release process, verifying a release, the security policy, governance, the assurance case, the licence and the third-party components. File and line references point into the repository at the commit this page was written from (6.2.24, master of 4 September 2026). Sections headed Unconfirmed or Contradictions record what could not be verified or where documents disagreed, and are left in on purpose. The build graph, the pre-flight table and the CI diagrams were added on 8 September 2026 and drawn from build/, build/preflight-tests.ps1 and .github/workflows/ as they stand in 6.2.28.
Verified 2026-09-04 against the working tree at f13ac06fc (branch server-fixes-wave, v6.2.24-5-gf13ac06fc) and the GitHub repository Progressiverobot/hmailserver via gh api. Paths are relative to the repository root unless stated. "(doc)" means the fact is what a document says and was not independently checkable from code; "(code)" means it was grepped/parsed; "(gh)" means it came from the GitHub API.
- Product: hMailServer, a fork of the original Windows mail server (SMTP/IMAP/POP3), maintained by Christopher Holloway / Progressive Robot Ltd (source: README.md:7-9)
- Repository: https://github.com/Progressiverobot/hmailserver (source: GOVERNANCE.md:5)
- Current version 6.2.28, build 38:
HMAILSERVER_VERSION "6.2.28",HMAILSERVER_VERSION_NUMERIC 6,2,28,38,HMAILSERVER_BUILD 38(source: hmailserver/source/Server/Common/Application/Version.h:5-7, code) - The same version is stamped in exactly seven .csproj
<Version>values: ControlPanel, DataDirectorySynchronizer, DBSetup, DBSetupQuick, DBUpdater, ImportTool, Shared (source:grep -n "<Version>" hmailserver/source/Tools/*/*.csproj, code; RELEASE.md:48-49 says "all seven") - Installer stamp:
AppVersion=6.2.28,OutputBaseFilename=hMailServer-6.2.28-x64,VersionInfoVersion=6.2.28.0(the fourth component stays 0 on purpose) (source: hmailserver/installation/section_setup_64.iss:2,6,10, code) - Schema:
REQUIRED_DB_VERSION 6031(source: hmailserver/source/Server/Common/Application/Constants.h:173, code). README.md:110 still says "Database version 6027" - stale, see section 17. - Latest published release: v6.2.28, published 2026-09-08T07:31:17Z, not draft, not prerelease, six assets:
hMailServer-6.2.28-x64.exe,hmailserver.spdx.json,hmailserver.cyclonedx.json, each with a.cosign.bundle(source:gh release view v6.2.28 --json assets, gh). v6.2.27 was published on 2026-09-07, v6.2.25 and v6.2.26 on 2026-09-06. - Tags present: v6.2.19 ... v6.2.22-pre1..pre6, v6.2.23-alpha1, v6.2.23-alpha2, v6.2.24, v6.2.25, v6.2.26, v6.2.27, v6.2.28 (source:
git tag -l 'v*', code) - v6.2.23-alpha1 is a lightweight tag (
git cat-file -t= commit); v6.2.23-alpha2 and every tag since (v6.2.24 to v6.2.28) are annotated tag objects (source:git cat-file -t refs/tags/<tag>, code; matches SECURITY.md "from v6.2.23-alpha2 on") - Badges: OpenSSF Best Practices project 14187 and OpenSSF Scorecard (source: README.md:4-5). Best Practices level is "Passing" at 100% (Basics 13/13, Change Control 9/9, Reporting 8/8, Quality 13/13, Security 16/16, Analysis 8/8) (source: https://www.bestpractices.dev/projects/14187, fetched 2026-09-04)
- Supported platforms: 64-bit Windows only, Windows 10 1607 / Server 2016 (build 14393) upward, enforced by the installer (source: README.md:127-129, doc)
- Compiler: Visual Studio 2026, platform toolset
v145, x64 only (source: hmailserver/source/Server/hMailServer/hMailServer.vcxproj:22,29<PlatformToolset>v145</PlatformToolset>, code; README.md:97; .github/CONTRIBUTING.md:12) - MSVC version: the tree pins the toolset family only - the native-dependencies action requires a
14.5*MSVC directory ("The v145 (14.5x) toolset is not installed") (source: .github/actions/native-dependencies/action.yml:77-82, code); the v6.2.24 release notes named the machine's compiler as MSVC 14.51. - Windows SDK: the project pins only
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>(latest installed) (source: hMailServer.vcxproj:17, code). RELEASE.md:76 and the v6.2.24 notes name "Windows SDK 10.0.26100" as the toolchain used - that is the machine's SDK, not a project pin. - VS workloads required: ".NET desktop development" (or "Managed Desktop Build Tools"), "Desktop development with C++"; components "C++ ATL for latest v145 build tools (x86 & x64)" and a Windows 10/11 SDK (source: README.md:195-199, doc)
- winget one-liner:
winget install Microsoft.VisualStudio.BuildTools --override "--quiet --wait --norestart --add Microsoft.VisualStudio.Workload.VCTools;includeRecommended --add Microsoft.VisualStudio.Component.VC.ATL --add Microsoft.VisualStudio.Workload.ManagedDesktopBuildTools"(source: README.md:203-205, doc) - Other required software: Inno Setup 6 (
winget install JRSoftware.InnoSetup, installer only), Perl 5 / Strawberry (OpenSSL only), Python 3 (libpq only) (source: README.md:180-185, doc). README.md:180 also lists "An installed version of hMailServer 5.7 or later (configured with a database)" - inherited upstream text. - MSBuild is located with vswhere (
-latest -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe) (source: build/Find-MsBuild.ps1:10-19, code) - Native libraries live OUTSIDE the tree under the
hMailServerLibsenvironment variable; the project references$(hMailServerLibs)\boost_1_92_0,$(hMailServerLibs)\openssl-4.0.2,$(hMailServerLibs)\postgresql-18.3(source: hMailServer.vcxproj:76,100, code; post-build.bat:12-18).build/Get-LibraryVersions.ps1parses those paths back out (openssl=4.0.2, boost=1.92.0, postgresql=18.3) for the CI cache keys. - Scripted route:
libraries\build-openssl.ps1 -Version 4.0.2,libraries\build-boost.ps1 -Version 1.92.0andlibraries\build-pgsql.ps1each download one source archive, verify it against a SHA-256 pinned in the script and build it under%hMailServerLibs%(source: README.md:287-289; libraries/build-openssl.ps1:54-94, code) - OpenSSL 4.0.x build:
Perl Configure no-asm VC-WIN64A --prefix=%cd%\out64 --openssldir=%cd%\out64 -D_WIN32_WINNT=0x0A00,nmake clean,nmake build_libs,nmake install_dev install_runtime_libs(notinstall_sw) (source: README.md, doc). Runtime DLLs copied arelibcrypto-4-x64.dllandlibssl-4-x64.dll(source: hmailserver/source/Server/hMailServer/post-build.bat:12-15, code) - PostgreSQL 18.3 libpq build: winflexbison on PATH,
py -m pip install meson ninja, thenmeson setup builddir --buildtype=release -Dssl=openssl -Dauto_features=disabled -Dextra_include_dirs=%hMailServerLibs%\openssl-4.0.2\out64\include -Dextra_lib_dirs=%hMailServerLibs%\openssl-4.0.2\out64\libandmeson compile -C builddir src/interfaces/libpq/libpq:shared_library(source: README.md:325, doc). Output copied frompostgresql-18.3\builddir\src\interfaces\libpq\*.dll(source: post-build.bat:18, code) - Boost 1.92.0 build:
bootstrapthenb2 debug release threading=multi link=static --with-thread --with-filesystem --with-regex --with-chrono --with-atomic address-model=64 stage --build-dir=out64 -j 4 define=BOOST_USE_WINAPI_VERSION=0x0A00(source: README.md:335-336, doc) -
libraries/build-openssl.ps1,build-boost.ps1andbuild-pgsql.ps1(sharingbuild-common.ps1) each download one source archive from the project's own release server, verify it against a SHA-256 pinned in the script, and build it outside the tree under%hMailServerLibs%; nothing they fetch is committed (source: libraries/build-openssl.ps1:54-94; hmailserver/docs/ThirdPartyBinaries.md:48-54, code) - .NET SDK pinned to 10.0.303,
rollForward latestFeature,allowPrerelease false(source: global.json:3-6, code) - All ten .csproj under source/Tools target
net10.0-windows(ControlPanel, ControlPanel.Core, ControlPanel.Tests, DataDirectorySynchronizer, DBSetup, DBSetupQuick, DBUpdater, ImportTool, ImportTool.Tests, Shared) (source:grep TargetFramework hmailserver/source/Tools/*/*.csproj, code) - Control Panel assembly name is
hMailCP(WPF, WinExe) (source: hmailserver/source/Tools/ControlPanel/ControlPanel.csproj:4-15, code) - NuGet lock files are enforced:
RestorePackagesWithLockFile=trueandEnableWindowsTargeting=truefor every Tools project (source: hmailserver/source/Tools/Directory.Build.props:17,33, code); CI restores with--locked-mode(source: .github/workflows/ci.yml:65,75,113) - The regression suite targets .NET Framework 4.8.1 (
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>) with NUnit 4.6.1, NUnit.ConsoleRunner 3.22.0, NUnit3TestAdapter 6.3.0 (source: hmailserver/test/RegressionTests/RegressionTests.csproj:38; hmailserver/test/RegressionTests/packages.config:31-33, code) - The .NET tools build against a checked-in TlbImp wrapper
hmailserver/source/Tools/Interop/Interop.hMailServer.dll, so no registered typelib is needed fordotnet build(source: hmailserver/source/Tools/Interop/README.md:3-7; ci.yml:6-7) - Building on a machine with a production hMailServer: pass
/p:PreBuildEventUseInBuild=false /p:PostBuildEventUseInBuild=false- build.ps1 already does (source: README.md:295; build/build.ps1:44-45, code) - One build tree; the service holds the output binary, so stop the service before linking and never build during a regression run (source: ARCHITECTURE.md "Building")
- Server:
build\build.ps1 -Configuration Release(default is Debug;-Cleanruns /t:Clean first). Runs MSBuild onhmailserver\source\Server\hMailServer\hMailServer.slnwith/m /p:Configuration=<cfg> /p:Platform=x64 /p:PreBuildEventUseInBuild=false /p:PostBuildEventUseInBuild=false, log tologs\build-<cfg>.log(source: build/build.ps1:4-66, code).-Asserts(added 5 Sep 2026, Release only) passes/p:KeepAssertions=true, which definesHM_KEEP_ASSERTIONS: the server's ownHM_ASSERTmacro (StdAfx.h; three modes - Debug = CRT assert, Release = compiled out, kept = reported) then reports a violated assertion as Critical HM6364 through ErrorManager naming expression, file and line, and carries on; loglogs\build-Release-asserts.log; the dynamic-analysis build, never the one that ships.Diagnostics.AssertionsEnabledsays which binary is running andDiagnostics.TriggerAssertion()provokes one (source: build/build.ps1; hMailServer.vcxproj KeepAssertions group; StdAfx.h; COM/InterfaceDiagnostics.cpp) - Server post-build (elevates via UAC):
build\post-build.ps1 -Configuration Release- runspost-build.bat <hMailServerLibs> <outDir> <exe> <intDir>, which doesNET STOP hMailServer, copies OpenSSL, libpq, MariaDB Connector/C (libraries\mariadb-connector-c-3.4.9\libmysql.dll+plugin\*.dll) andhMailServer.tlbbeside the exe, thenhMailServer.exe /Register(source: build/post-build.ps1:8-32; hmailserver/source/Server/hMailServer/post-build.bat:10-42, code) - Output location:
hmailserver\source\Server\hMailServer\x64\<Configuration>\hMailServer.exe(source: build/post-build.ps1:16-17, code) - Admin/setup tools:
build\build-tools.ps1(default Release) runsdotnet publish <proj>.csproj -c <cfg> -o <proj>\publishfor DBSetup, DBSetupQuick, DBUpdater, DataDirectorySynchronizer, ImportTool, deleting each publish folder first (source: build/build-tools.ps1:21-34, code). Solution:hmailserver/source/Tools/hMailServer Tools.sln(projects Shared, DBSetup, DBSetupQuick, DBUpdater, DataDirectorySynchronizer, ImportTool) (source:grep Project( "hMailServer Tools.sln", code) - Control Panel: NOT covered by build-tools.ps1; it is a separate
dotnet publishofhmailserver\source\Tools\ControlPanel\ControlPanel.csprojinto itspublish\folder (source: build/build-tools.ps1:7-11; RELEASE.md:52-55). Solutionhmailserver/source/Tools/ControlPanel.slnholds ControlPanel, ControlPanel.Core, ControlPanel.Tests (source:grep Project( ControlPanel.sln, code). CI's publish command isdotnet publish hmailserver/source/Tools/ControlPanel/ControlPanel.csproj -c Release -o publish --no-build(source: ci.yml:71) - Tests:
build\build-tests.ps1(default Debug) first restores the parenthmailserver\test\hMailServer Tests.sln(/t:Restore /p:RestorePackagesConfig=true) then MSBuildshmailserver\test\RegressionTests\RegressionTests.slnx64, log tologs\build-tests.log(source: build/build-tests.ps1:18-64, code) - Installer: ISCC on
hmailserver\installation\hMailServer64.iss(Inno Setup 6) (source: README.md:292-293; RELEASE.md:88). ISCC on this machine:C:\Users\chris\AppData\Local\Programs\Inno Setup 6\ISCC.exe(local, code).hMailServer64.issreadshMailServerLibsand definesDOTNET_MAJOR "10",DOTNET_CHANNEL "10.0",DOTNET_RUNTIME_FILE "windowsdesktop-runtime-10.0-win-x64.exe"(source: hmailserver/installation/hMailServer64.iss:1-19, code) - Bundled .NET runtime:
build\get-dotnet-runtime.ps1(default-Channel 10.0) downloadshttps://aka.ms/dotnet/10.0/windowsdesktop-runtime-win-x64.exetohmailserver\installation\DotNet\(gitignored, 55+ MB) and rejects files under 40 MB (source: build/get-dotnet-runtime.ps1:16-38, code) - COM wrapper regeneration after any
hMailServer.idlchange and after a Release server build:build\regenerate-interop.ps1runsTlbImp.exe hMailServer.tlb /out:Interop.hMailServer.dll /namespace:hMailServer /machine:X64 /silentAND rewrites the wrapper's SHA-256/size inhmailserver/docs/third-party-binaries.json(source: build/regenerate-interop.ps1:30-130, code). TlbImp default pathC:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8.1 Tools\x64\TlbImp.exe(source: build/regenerate-interop.ps1:31) - COM re-registration for a NEW interface (elevated):
build\register-com.ps1(/RegisterTypeLib, or/Registerwith-IncludeService) (source: build/register-com.ps1:39-93, code) - Fuzzing (separate, clang-cl):
.\fuzz\build-fuzz.ps1then.\fuzz\run-fuzz.ps1 -Target mime_message_fuzzer -Minutes 5; needs "C++ Clang tools for Windows"; never touches hMailServer.sln or the service (source: fuzz/README.md:16-26, doc). Harnesses: mime_message_fuzzer, mime_header_fuzzer, mime_decode_fuzzer; dictfuzz/dict/mime.dict;fuzz/regression/committed;corpus/,build/,bin/,artifacts/are generated not committed (source: fuzz/README.md:32-45;ls fuzz/harness fuzz/dict fuzz/regression, code)
Nothing here builds everything. Five separate commands produce five separate outputs, and two of them have an ordering constraint that is easy to miss — the interop wrapper is generated from the server build and consumed by the tools build, so a release that regenerates it must do so between them.
flowchart TB
subgraph outside["Outside the tree - %hMailServerLibs%"]
OSSL["OpenSSL 4.0.2<br/>libraries/build-openssl.ps1"]
BOOST["Boost 1.92.0<br/>libraries/build-boost.ps1"]
PGL["PostgreSQL 18.3 libpq<br/>libraries/build-pgsql.ps1"]
end
SLN["hMailServer.sln<br/>C++, v145, x64"]
EXE["hMailServer.exe<br/>+ hMailServer.tlb"]
POSTB["build/post-build.ps1 - elevated<br/>stops the service, copies OpenSSL,<br/>libpq and MariaDB Connector/C DLLs,<br/>hMailServer.exe /Register"]
TLBIMP["build/regenerate-interop.ps1<br/>TlbImp + rewrites the SHA-256<br/>in docs/third-party-binaries.json"]
INTEROP["Interop.hMailServer.dll<br/>committed under source/Tools/Interop"]
TOOLS["hMailServer Tools.sln<br/>DBSetup, DBSetupQuick, DBUpdater,<br/>DataDirectorySynchronizer, ImportTool"]
CP["ControlPanel.sln<br/>hMailCP - published separately"]
TESTS["RegressionTests.sln<br/>net481, x64 only"]
DOTNET["build/get-dotnet-runtime.ps1<br/>windowsdesktop-runtime-10.0-win-x64.exe"]
ISS["ISCC hMailServer64.iss"]
SETUP["hMailServer-6.2.28-x64.exe"]
OSSL --> SLN
BOOST --> SLN
PGL --> SLN
SLN --> EXE
EXE --> POSTB
EXE -->|"only when hMailServer.idl changed"| TLBIMP
TLBIMP --> INTEROP
INTEROP --> TOOLS
INTEROP --> CP
INTEROP --> TESTS
EXE --> ISS
TOOLS --> ISS
CP --> ISS
DOTNET --> ISS
ISS --> SETUP
| Output | Command | Configuration default | Lands in |
|---|---|---|---|
hMailServer.exe |
build\build.ps1 |
Debug (pass -Configuration Release) |
hmailserver\source\Server\hMailServer\x64\<cfg>\ |
| Registered service + runtime DLLs | build\post-build.ps1 |
Release when told | beside the exe; elevates via UAC |
Interop.hMailServer.dll |
build\regenerate-interop.ps1 |
— |
hmailserver\source\Tools\Interop\ (committed) |
| The five admin tools | build\build-tools.ps1 |
Release | each project's own publish\
|
hMailCP (Control Panel) |
dotnet publish ControlPanel.csproj -c Release -o publish |
— |
ControlPanel\publish\ — not covered by build-tools.ps1
|
RegressionTests.dll |
build\build-tests.ps1 |
Debug | hmailserver\test\RegressionTests\bin\x64\Debug\ |
| The installer | ISCC on hMailServer64.iss
|
— | installation\Output\ |
Three traps this graph encodes:
- A stale interop wrapper still compiles. The tools use a small, stable subset of the COM API, so nothing fails — the members added this release are simply invisible to them. That is why regenerating is a release step rather than something a build error reminds you about.
- Regenerate the wrapper after any interface-ordering fix, never before, or the old vtable layout is baked into the shipped wrapper permanently.
- The tests are always built x64. An AnyCPU build of the same project also runs, against stale assemblies, and passes tests it never executed.
- Warnings as errors:
<TreatWarningAsError>true</TreatWarningAsError>(/WX),<WarningLevel>Level3</WarningLevel>, Debug and Release (source: hMailServer.vcxproj:83-84,153-154, code) - Control Flow Guard:
<ControlFlowGuard>Guard</ControlFlowGuard>compile +/guard:cflink, Debug and Release (source: hMailServer.vcxproj:87,96,164,173, code) - Reproducible Release: compiler
/Zm200 /Brepro /d1trimfile:$(SolutionDir), linker/ignore:4099 /guard:cf /Brepro /pdbaltpath:%_PDB%(source: hMailServer.vcxproj:165,173, code) -
OPENSSL_NO_FILENAMESdefined in every configuration (source: hMailServer.vcxproj:64,77,137,149,168, code) -
<ExceptionHandling>Async</ExceptionHandling>(/EHa) in Debug and Release (source: hMailServer.vcxproj:79,150, code) - /GS, /NXCOMPAT, /DYNAMICBASE are NOT set explicitly in the vcxproj (no BufferSecurityCheck/DataExecutionPrevention/RandomizedBaseAddress elements) - they are MSVC x64 defaults. Verified on the built binary instead:
x64\Release\hMailServer.exePE DllCharacteristics 0xC160 = HIGH_ENTROPY_VA, DYNAMIC_BASE, NX_COMPAT, GUARD_CF, TERMINAL_SERVER_AWARE on; LOAD_CONFIG directory present (320 bytes) (source: PE header parse of the local Release exe, code) - The PE-flag check above was made on the 6.2.24 binary (SHA-256
64406163b1a3a8a865e34d74883b5e2a05a5a1c476b500b26745cde67d8a989b, size 10,171,904, identical to the hash in the v6.2.24 release notes); the project flags have not changed since. The shipped 6.2.28 binary is hMailServer.exe 6.2.28.38, SHA-2569E89C1E3ABF4DD36560B0B5F3515BDA3DAB8B96F00EF35DA5376A9B60176BD15; the installerhMailServer-6.2.28-x64.exeis 79,324,526 bytes, SHA-256FCC791855E9C1C4F3B2D3B8592B4D9CCBAC000DA866BBF8617561415078D5054(source: v6.2.28 release notes, verification section, andgh release view v6.2.28 --json assets, gh) - Reproducibility claim: two clean Release builds give a byte-identical exe; first shown 22 August 2026; verified per release at RELEASE.md step 8 (source: ASSURANCE-CASE.md "Residual risk"; RELEASE.md:69-78, doc)
- CFG cost measured: full 1,838-test gate 31 minutes vs about 55 before; exe grew about 97 KB (source: ASSURANCE-CASE.md "Residual risk", doc)
- Runner:
build\run-tests.ps1runshmailserver\test\packages\NUnit.ConsoleRunner.3.22.0\tools\nunit3-console.exe hmailserver\test\RegressionTests\bin\x64\Debug\RegressionTests.dll --labels=All, log tologs\run-tests.log;-StopOnErroradds/stoponerror(not for release runs);-Where "<expr>"adds--where=for a subset (source: build/run-tests.ps1:14-69, code) - Test assembly is the Debug x64 build even for release gates (source: build/run-tests.ps1:28, code)
- Pre-flight first:
build\preflight-tests.ps1(-Cleanremoves a stale ERROR log) (source: RELEASE.md:23-27; .github/PULL_REQUEST_TEMPLATE.md:16-18) - Pre-flight checks (in order): service exists and its PathName is the repo Release exe; service running; no stray
HKLM\SOFTWARE\hMailServer\InstallLocationin either registry view; COM auth as Administrator/testar;Domains.Count -eq 1;Settings.TCPIPPorts.Count -eq 4;Database.CurrentVersion -eq RequiredVersion; no stale ERROR log; clamd listening on 3310; serviceSpamAssassinJAMexists; listeners on 25, 110, 143; VPN adapter warning (Proton|WireGuard); NUnit runner and RegressionTests.dll present; no orphan .cs files missing from RegressionTests.csproj (source: build/preflight-tests.ps1:19-159, code) - Test count: 2,127
[Test]attributes across the suite at v6.2.28 (2,024 at v6.2.27); RegressionTests.csproj lists 348<Compile Include>entries explicitly (no glob) (source:grep -c "^\s*\[Test\]"over hmailserver/test/RegressionTests; csproj, code). The v6.2.28 gate was 2,127 tests, 2,119 passed, 0 failed, 8 skipped - the 7 explicit stress skips and one ignored where STARTTLS is not offered on the plain IMAP port of this bench - on the stamped binary. The notes also record 65 schema probes passing against a 6031 database built from the create script; unlike v6.2.27's they say nothing about the Control Panel's own tests (source: v6.2.28 release notes, gh) - Every source file must be listed in RegressionTests.csproj or it is never compiled; pre-flight fails on orphans (source: ARCHITECTURE.md "Tests"; preflight-tests.ps1:133-159)
- Tests that provoke a reported error must clear it with
CustomAsserts.AssertReportedError(...);PerformBasicSetupcallsAssertNoReportedError(source: ARCHITECTURE.md "Tests", doc) - Run elevated: the suite starts/stops the hMailServer and SpamAssassin services; unelevated those tests report inconclusive (source: README.md:519-520, doc)
- Never
dotnet testthe RegressionTests project; it is .NET Framework/packages.config and is built with MSBuild (source: build-tests.ps1; RegressionTests.csproj:38, code) - Control Panel unit tests:
dotnet test hmailserver/source/Tools/ControlPanel.Tests/ControlPanel.Tests.csproj --configuration Release --collect:"XPlat Code Coverage"(cobertura) in CI; the coverage upload to GitHub isfail-on-error: falsebecause the Code Quality repository setting is deliberately off (source: ci.yml:77-148, code) - Import Tool unit tests:
dotnet test hmailserver/source/Tools/ImportTool.Tests/ImportTool.Tests.csproj -c Release --no-buildruns in the "Build .NET tools" job after the solution build (the Maildir reader: folders, messages, file-name flags, line endings) (source: ci.yml:118-126, code) - Other test projects under hmailserver/test (PerformanceTests, MemoryTests, StressTest, TestBedUI, TestInvalidConnections, VMTestRunner.Console, PerformanceTest, hMailServer.PerformanceTests, hMailServer.PerformanceTests.Console, hMailServer.Test.Infrastructure) exist but are built by nothing (source:
find hmailserver/test -name *.csproj; no reference in build/ or .github/workflows, code)
build/preflight-tests.ps1 runs these in order and stops at the first that fails.
Every one of them corresponds to a run that was actually lost. The right-hand column
is what the failure looks like if you skip the pre-flight and run the suite anyway —
which is the reason the script exists, because none of those symptoms names its cause.
| # | Check | What it is really catching | Symptom without the pre-flight |
|---|---|---|---|
| 1 | Service exists, PathName is the repo Release exe |
Somebody ran the installer on this machine and it re-pointed the service at C:\Program Files\...
|
Every run is green — against the installed binary, not the one you just built |
| 2 | Service running | A failed link left the service stopped | 100% of tests fail in fixture setup |
| 3 | No stray HKLM\SOFTWARE\hMailServer\InstallLocation in either registry view |
The same installer, second half of its damage: the INI lookup is redirected | The server reports "Running" with empty configuration |
| 4 | COM auth as Administrator / testar
|
The bench credential was changed or cleared | Setup throws on the first COM call |
| 5 | Domains.Count -eq 1 |
A killed fixture left a domain behind, or removed the test domain | Fixtures that assume a clean domain list fail in unrelated places |
| 6 | Settings.TCPIPPorts.Count -eq 4 |
A TLS fixture was interrupted: it registers twelve extra ports and removes them in teardown | Port-count sixteen; TLS fixtures fail on "already exists" |
| 7 | Database.CurrentVersion -eq RequiredVersion |
The bench database was never moved forward past a schema bump | The service refuses the connection and nothing in the failure says "database" |
| 8 | No stale ERROR log | An aborted run left the deliberate scanner error behind | 100% of tests fail before doing anything |
| 9 |
clamd listening on 3310 |
ClamAV not started, or still loading signatures | Anti-virus fixtures fail open — the server has no verdict, so nothing is detected |
| 10 | Service SpamAssassinJAM exists |
Wrapped under a different name | The fixture that stops and restarts it cannot find it |
| 11 | Listeners on 25, 110, 143 | Another mail server, or a port left bound | Connection-refused failures that look like protocol bugs |
| 12 | VPN adapter warning (Proton, WireGuard) |
Loopback rewriting | Fixtures that bind a specific local address pick the wrong one |
| 13 | NUnit runner and RegressionTests.dll present |
The tests were never built, or built AnyCPU | The runner exits having run nothing |
| 14 | No orphan .cs files missing from RegressionTests.csproj
|
A new test file nobody added to the explicit file list | The test is invisible: it is not run and a green suite says nothing about it |
Pre-flight passed - safe to run the suite is the state Regression Test Environment
builds a machine towards.
- Real server, nothing mocked: live SMTP/IMAP/POP3 sockets, COM API, live SpamAssassin and ClamAV, real TLS 1.2/1.3 handshakes. DNS is the one exception since 5 September 2026: the suite serves its own zone (
Shared/SuiteDns.cs, a[SetUpFixture]that binds a FakeDnsServer on 127.0.0.1 and pointsDNSServerat it for the run; DMARC, SPF and DKIM fixtures add the records they need) so no test resolves a live name (source: SuiteDns.cs; RegressionEnvironment.md:189-191, code). README.md:13 and ARCHITECTURE.md:170 still say "DMARC against live DNS" - stale. - The service must run from the repository Release build
hmailserver\source\Server\hMailServer\x64\Release\hMailServer.exe, not an installed copy (source: hmailserver/docs/RegressionEnvironment.md:35-41; preflight-tests.ps1:20-24) - Database: SQL Server Compact 4.0 x64 from
hmailserver\installation\SQLCE; bench DB created once via COMDatabase.CreateInternalDatabase()+Reinitialize(), thereafter upgraded never recreated; move it forward withbuild\upgrade-test-database.ps1(through the service's COM API, no elevation) (source: RegressionEnvironment.md:63-87; build/upgrade-test-database.ps1:4-22, code) - Data directory convention
C:\HMTest\Data(short, to avoid MAX_PATH) (source: RegressionEnvironment.md:89-95) - Exactly one domain and exactly four TCP/IP ports at start: SMTP 25, POP3 110, IMAP 143 and the SMTP submission port; the TLS fixtures add twelve more and remove them in teardown (source: RegressionEnvironment.md:96-105; preflight-tests.ps1:53-59)
- COM credentials:
Administrator/testar(blank fallback) - a bench credential, not a secret (source: RegressionEnvironment.md:107-110; preflight-tests.ps1:50) - ClamAV:
C:\clamav\clamd.exe(hard-coded inCustomAsserts),TCPSocket 3310,TCPAddr 127.0.0.1, runs as a bare process (source: RegressionEnvironment.md:112-120) - SpamAssassin: Windows service named
SpamAssassinJAMwrappingspamd.exe -i 127.0.0.1 -A 127.0.0.1 -p 783(source: RegressionEnvironment.md:127-134). README.md:527-535 gives an alternative CPAN build with--port 783. - Without SpamAssassin/ClamAV the dependent tests report inconclusive rather than failing (source: README.md:512, doc)
- The suite wipes domains and accounts; never run it against production (source: README.md:514; RegressionEnvironment.md:17-18)
- Code of Conduct: Contributor Covenant (source: .github/CODE_OF_CONDUCT.md:1; CONTRIBUTING.md:5-6)
- DCO sign-off:
git commit -saddsSigned-off-by:; no CLA; fix isgit commit --amend -s(source: .github/CONTRIBUTING.md:40-48) - The DCO check (
.github/workflows/dco.yml, job "Signed-off-by on every commit") runs onpull_requestto master only, requires the trailer to contain the commit AUTHOR's email, and is skipped entirely when the PR author isdependabot[bot]or hasauthor_associationOWNER or MEMBER (source: dco.yml:28-42,59-70, code) - The DCO job is NOT among the nine required status checks on master (source:
gh api repos/Progressiverobot/hmailserver/rulesets/21165267, gh) - see section 8 - Branch from
master; version branches are bug-fix only; one logical change per PR; add/update regression tests; parameterised SQL exclusively; new server-wide optional features follow the INI-settings pattern (IniFileSettingsgetter + Server features dialog control) (source: CONTRIBUTING.md:50-57) - Coding style:
.editorconfigsetsindent_style = space,indent_size = 3for*.{h,cpp,cs}(source: .editorconfig:4-6, code). Enforced by editorconfig-checker v3.11.3 (installed by the action, then run explicitly - the action alone checks nothing) anddotnet format --verify-no-changeson the Tools solution and ControlPanel.csproj; exclusions live in.editorconfig-checker.jsonat the repository root (source: .github/workflows/style.yml:9,40-52,102-127; .editorconfig-checker.json, code). - Every source file carries a copyright line and
SPDX-License-Identifier: AGPL-3.0-or-later; enforced bypython3 build/add-license-headers.py --check; MIDL output (dlldata.c,hMailServer_i.c,hMailServer_p.c) and the directorieslibraries/,zlib(vendored zlib source under its own licence; new in 6.2.28),obj,bin,publish,packages,Outputare skipped (source: build/add-license-headers.py:53-59; style.yml:55-66, code) - The "SPDX identifier on every source file" job also runs, in order:
python3 build/check-mnemonics.py(every static Control Panel caption has an Alt-key mnemonic, no two on one view/method share one),python3 build/check-localisation.py(the generated English catalogueResources/Strings.resxmatches theL(...)/F(...)/N(...)/{loc:L}marks in the source - run it with--writeafter adding a caption; every language keeps its English's{n}placeholders and Alt keys; each of the 17 languages inCOMPLETEmust translate every key; a file inLOCALISEDmay carry no unmarked caption),python3 build/check-catalogues.py(translations keep the server's literal names, page titles and numbers),python3 build/check-ini-coverage.py(every[Settings]keyIniFileSettingsreads is named somewhere in the Control Panel and is read throughIniFileSettings),python3 build/check-authz-choke-point.py(onlyACLManagerdecides folder access). All five gate a PR through that required check; the mnemonic and ACLManager checks landed for 6.2.25, the three localisation and INI-coverage checks for 6.2.28 (source: .github/workflows/style.yml:65-100; build/check-localisation.py:52-55, code) - Compiler runs with /WX; code must build warning-free; C# builds with
-warnaserrorin CI (source: CONTRIBUTING.md:19; ci.yml:68,116) - PR template checklist: builds warning-free with build/build.ps1; regression suite passes after preflight; new behaviour covered by tests; parameterised SQL; schema changes include MySQL, MS SQL and PostgreSQL scripts in
source/DBScripts/; new settings via COM API or hMailServer.INI pattern (source: .github/PULL_REQUEST_TEMPLATE.md:14-22) -
good first issuelabel marks bounded tasks tied to Roadmap.md gaps (source: CONTRIBUTING.md:33-38) - CODEOWNERS:
@chrisholloway5owns everything, with explicit entries for .github, workflows, SECURITY.md, ThirdPartyBinaries docs, libraries/, installation/, Interop/, TCPIP/, Crypt.cpp/h, LDAP/, RELEASE.md, build/; "Require review from Code Owners" is deliberately OFF because a sole owner cannot approve their own PR (source: .github/CODEOWNERS:1-58, code; rulesetrequire_code_owner_review: false, gh) - Support routing: defects to Issues; questions to Discussions; general hMailServer questions to the hMailServer forum; security to advisories (source: .github/SUPPORT.md; .github/ISSUE_TEMPLATE/config.yml)
- Dependabot: NuGet weekly grouped (
dotnet-dependencies, limit 10) and GitHub Actions weekly grouped (limit 5) for both/and/.github/actions/native-dependencies; native C++ libs are pinned by hand in hMailServer.vcxproj and the digest tables oflibraries/build-*.ps1(source: .github/dependabot.yml, code) - Commit identity for the maintainer: commit as chrisholloway5, no co-author trailers (source: RELEASE.md:91-92)
- Contributions are licensed AGPLv3 (source: CONTRIBUTING.md:66-69)
Twelve workflow files under .github/workflows/ (names as declared, code):
-
ci.yml"CI" - push/PR to master, dispatch. Jobs: "Build Control Panel (.NET 10)" (regenerates and verifiesSettingsSearchIndex.g.cs, restore --locked-mode, build -warnaserror, publish, test with coverage), "Build .NET tools" (locked restore, build -warnaserror,./build/build-tools.ps1), "upload-coverage-csharp" (source: ci.yml:12-148) -
codeql.yml"CodeQL" - push/PR/weekly Monday 04:32 UTC/dispatch. Job "Analyze (csharp)" on every push/PR,security-and-quality, build-mode manual, obj/bin results filtered from SARIF. Job "Analyze (c-cpp)" on push to master, schedule and dispatch but NOT on pull requests (if: github.event_name != 'pull_request'); GitHub-hostedwindows-2025-vs2026, native libraries restored or built by.github/actions/native-dependenciesbefore CodeQL init,security-extended, full build viabuild\build.ps1 -Configuration Release(Debug selectable on dispatch), 240-minute timeout; the status-check name carries the image, "Analyze (c-cpp) (windows-2025-vs2026)" (source: codeql.yml:34-47,160-259; .github/codeql/codeql-config.yml) -
dco.yml"DCO" - PR only; job "Signed-off-by on every commit" (source: dco.yml:1-37) -
dependency-review.yml"Dependency review" - PR only;fail-on-severity: high(source: dependency-review.yml:1-30) -
installer-smoke.yml"Installer smoke test" - dispatch only; job "Install on a throwaway runner and verify": downloadshMailServer-*-x64.exefrom a release tag or aninstallerartifact, runs/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /TYPE=full /LOG=, 10-minute bound, checks service PathName, Running, listeners on 25/110/143,New-Object -ComObject hMailServer.Application, keeps the log, uninstalls (source: installer-smoke.yml:18-223) -
sbom.yml"SBOM" - push to master,release: created, dispatch withrelease_tag; job "Generate SBOM (SPDX + CycloneDX)" with anchore/sbom-action (Syft), thenbuild/merge-native-dependencies-into-sbom.ps1adds OpenSSL/Boost/libpq (versions parsed from hMailServer.vcxproj bybuild/native-dependencies.ps1), verifies every native PURL is present, uploads artifact (90 days) and attaches to the release (source: sbom.yml:24-133) -
scorecard.yml"OpenSSF Scorecard" - Sunday 04:17 UTC, push to master, dispatch;publish_results: truesince 5 September 2026 (the README badge and the scorecard.dev viewer read the public OpenSSF API); SARIF to code scanning (source: scorecard.yml:18-95, code) -
server-build.yml"Server build" - push/PR to master, dispatch (Release/Debug); job "Build server" on GitHub-hostedwindows-2025-vs2026(so the status-check name is "Build server (windows-2025-vs2026)"); the native libraries are restored from cache or built from source by.github/actions/native-dependencies(libraries/build-*.ps1, 30-45 minutes cold), thenbuild\build.ps1 -Configuration Release; uploads hMailServer.exe, .pdb, hMailServer.tlb and the OpenSSL/libpq DLLs as a 14-day artifact; 120-minute timeout; the regression suite is NOT run here - it still needs the maintainer's bench (source: server-build.yml:1-150, code) -
sign-release.yml"Sign release artefacts" -release: created, dispatch withtag; job "Sign and attach signatures": refuses a lightweight tag or one that failsverify-tagagainst.github/allowed_signers;cosign sign-blob --yes --bundle <file>.cosign.bundle; verifies with--certificate-identity-regexp "^https://github\.com/<repo>/"and--certificate-oidc-issuer https://token.actions.githubusercontent.com; uploads bundles; before signing it refuses a release with no asset named exactlyhMailServer-<tag without the leading v>-x64.exe, because the server's update checker (UpdateChecker.cpp:428-429, new in 6.2.28) builds that name from the tag and matches it on equality (source: sign-release.yml:38-189, name check at 139-160) -
style.yml"Coding style" - jobs "editorconfig-checker", "SPDX identifier on every source file", "dotnet format leaves the C# tree unchanged" (source: style.yml:22-82) -
upstream-watch.yml"Upstream watch" - monthly (0 6 1 * *) and dispatch; compares againsthmailserver/hmailserverafter the SHA in.github/upstream-sync;issues: write(source: upstream-watch.yml:14-35) -
verify-binary-provenance.yml"Binary provenance" - push/PR/dispatch; job "Verify committed binaries against the manifest": hash everyartifacts[]entry inhmailserver/docs/third-party-binaries.json, fail on changed/missing/unlisted binaries (Scorecard extension set + MZ/ELF/OLE sniff), warn onremove-*dispositions (source: verify-binary-provenance.yml:35-166) - All actions are pinned to full commit SHAs with version comments (source: every
uses:line, code)
Branch and tag protection (gh, ruleset API, 2026-09-04):
- Ruleset "Protect master: changes arrive by pull request" (id 21165267, active) on
refs/heads/master: rulesdeletion,non_fast_forward,pull_request(required_approving_review_count 0, require_code_owner_review false, dismiss_stale_reviews false, require_last_push_approval false, allowed merge methods merge/squash/rebase, require_extra_approval_for_unattributed_changes true),required_status_checkswithstrict_required_status_checks_policy: true - The nine required status checks, verbatim: "Build Control Panel (.NET 10)", "Build .NET tools", "Analyze (csharp)", "SPDX identifier on every source file", "editorconfig-checker", "dotnet format leaves the C# tree unchanged", "Verify committed binaries against the manifest", "Dependency review", "Build server (windows-2025-vs2026)"
- Not required: "Signed-off-by on every commit" (DCO), Scorecard, CodeQL c-cpp, SBOM, upstream watch
- Ruleset "Protect release tags" (id 20539388, active) on
refs/tags/v*:deletionandnon_fast_forwardblocked - Classic branch protection is not used (
/branches/master/protectionreturns 404 "Branch not protected"); protection is entirely via rulesets
Nine status checks are required on master. They come from six workflows; the other
six workflows either do not run on pull requests at all, or run and are advisory. The
diagram is the PR path only — the schedule and release paths are in the table below.
flowchart LR
PR["Pull request<br/>to master"]
subgraph runs["Workflows that run on a PR"]
direction TB
CI["CI - ci.yml<br/>windows-latest"]
SBW["Server build - server-build.yml<br/>windows-2025-vs2026, 120 min"]
CQ["CodeQL - codeql.yml<br/>csharp only on a PR"]
STY["Coding style - style.yml"]
BP["Binary provenance<br/>verify-binary-provenance.yml"]
DRV["Dependency review<br/>dependency-review.yml"]
DCO["DCO - dco.yml"]
end
subgraph req["The nine required checks"]
direction TB
R1["Build Control Panel (.NET 10)"]
R2["Build .NET tools"]
R3["Build server (windows-2025-vs2026)"]
R4["Analyze (csharp)"]
R5["editorconfig-checker"]
R6["SPDX identifier on every source file"]
R7["dotnet format leaves the C# tree unchanged"]
R8["Verify committed binaries against the manifest"]
R9["Dependency review"]
end
ADV["Signed-off-by on every commit<br/>runs, but NOT required -<br/>and skipped for OWNER, MEMBER<br/>and dependabot"]
MERGE["Merge - strict policy:<br/>the branch must be up to date<br/>with master first"]
PR --> CI
PR --> SBW
PR --> CQ
PR --> STY
PR --> BP
PR --> DRV
PR --> DCO
CI --> R1
CI --> R2
SBW --> R3
CQ --> R4
STY --> R5
STY --> R6
STY --> R7
BP --> R8
DRV --> R9
DCO --> ADV
R1 --> MERGE
R2 --> MERGE
R3 --> MERGE
R4 --> MERGE
R5 --> MERGE
R6 --> MERGE
R7 --> MERGE
R8 --> MERGE
R9 --> MERGE
The "SPDX identifier on every source file" job is doing far more than its name says. It runs six scripts in order, and any of them fails the required check:
flowchart TB
J["Job: SPDX identifier on every source file<br/>style.yml, ubuntu-latest"]
J --> A1["build/add-license-headers.py --check<br/>copyright line + SPDX on every source file"]
A1 --> A2["build/check-mnemonics.py<br/>every static Control Panel caption has an Alt key;<br/>no two on one view share one"]
A2 --> A3["build/check-localisation.py<br/>the English catalogue matches the source marks;<br/>all 17 COMPLETE languages translate every key"]
A3 --> A4["build/check-catalogues.py<br/>translations keep literal names, page titles, numbers"]
A4 --> A5["build/check-ini-coverage.py<br/>every Settings key the server reads<br/>has a Control Panel editor"]
A5 --> A6["build/check-authz-choke-point.py<br/>only ACLManager decides folder access"]
That is why adding one Control Panel caption is not a one-line change: a new caption
fails CI in every language until it is marked, the English catalogue is regenerated
with python3 build/check-localisation.py --write, and all 17 complete languages carry
a translation.
| Workflow | File | Runs on | Runner | Required | What a failure means |
|---|---|---|---|---|---|
| CI | ci.yml |
push/PR to master, dispatch | windows-latest | yes (2 checks) | The Control Panel or the .NET tools no longer build warning-free, a locked NuGet restore drifted, SettingsSearchIndex.g.cs is stale, or a Control Panel / Import Tool unit test failed |
| Server build | server-build.yml |
push/PR to master, dispatch | windows-2025-vs2026, 120 min | yes | The C++ server does not compile on a clean hosted machine with libraries built from source. The regression suite is not run here — that still needs the maintainer's bench |
| CodeQL | codeql.yml |
push/PR/weekly Mon 04:32 UTC/dispatch | windows-latest (csharp), windows-2025-vs2026 (c-cpp), 240 min | csharp only | A security-and-quality finding in C#. The C++ job uses security-extended and deliberately does not run on pull requests |
| Coding style | style.yml |
push/PR to master, dispatch | ubuntu-latest ×2, windows-latest ×1 | yes (3 checks) | Indentation drift, a missing SPDX header, an unformatted C# file, or any of the five Control Panel / INI / authorisation checks above |
| Binary provenance | verify-binary-provenance.yml |
push/PR to master, dispatch | ubuntu-latest | yes | A committed binary changed, went missing, or appeared without a docs/third-party-binaries.json entry. Regenerating the interop wrapper by hand without updating the manifest broke this twice in one day |
| Dependency review | dependency-review.yml |
PR only | ubuntu-latest | yes | A dependency change introduces a high-or-worse advisory |
| DCO | dco.yml |
PR only | ubuntu-latest | no | A commit lacks Signed-off-by: matching its author. Skipped entirely for dependabot[bot] and for authors with OWNER or MEMBER association |
| SBOM | sbom.yml |
push to master, release: created, dispatch with release_tag
|
ubuntu-latest | no | Syft could not build the SPDX/CycloneDX documents, or a native PURL (OpenSSL, Boost, libpq) is missing after the merge step |
| Sign release artefacts | sign-release.yml |
release: created, dispatch with tag
|
ubuntu-latest | no | A lightweight or unverifiable tag, or a release with no asset named exactly hMailServer-<tag without the v>-x64.exe
|
| OpenSSF Scorecard | scorecard.yml |
Sunday 04:17 UTC, push to master, dispatch | ubuntu-latest | no | Score regression. Published to the OpenSSF API since 5 September 2026; Branch-Protection and Code-Review are expected to fail on a single-maintainer repository |
| Upstream watch | upstream-watch.yml |
monthly 0 6 1 * *, dispatch |
ubuntu-latest | no | Nothing — it opens an issue listing upstream commits after the SHA in .github/upstream-sync
|
| Installer smoke test | installer-smoke.yml |
dispatch only | windows-latest | no | The installer does not install silently, or the installed service does not run, listen on 25/110/143 and answer a hMailServer.Application COM call |
Two structural facts about that table:
- Nothing in CI runs the regression suite. The 2,127-test gate is a bench-only step (RELEASE.md 8b and 9), which is why "green CI" and "green gate" are different claims and the release notes report them separately.
-
The two release workflows are dispatched by hand. GitHub delivers no
releaseevent for a draft release — measured here, not assumed — so therelease: createdtrigger only covers a release published without a draft, which is the path that can no longer attach anything. See Release Process.
The thirteen ordered steps of RELEASE.md (source: RELEASE.md:6-153, doc, with script facts checked in code):
- Freeze the code (RELEASE.md:8)
- Adversarial review of the complete diff BEFORE version stamping (RELEASE.md:10-17)
- Fix what survives; every defect fix gets a negative-control test that fails on the pre-fix binary (RELEASE.md:18-22)
- Pre-flight:
build\preflight-tests.ps1(-Clean) (RELEASE.md:23-27) -
build\check-roadmap.ps1reconciles Roadmap.md tick boxes against section counts and the contents table (RELEASE.md:28-31; build/check-roadmap.ps1:4-20) -
build\check-db-scripts.ps1builds a throwaway SQL CE database fromCreateTablesMSSQL.sqland applies everyUpgrade*MSSQLCE.sqlusing SQLScriptParser's blank-line splitting (default assemblyC:\Program Files\Microsoft SQL Server Compact Edition\v4.0\Desktop\System.Data.SqlServerCe.dll); plusbuild\check-schema-versions.ps1(pwsh 7 only) which cross-checks REQUIRED_DB_VERSION, DBUpdater's LoadScripts table, GetDatabaseVersionName, the Upgradeto.sql files (four per step) and SchemaVerification.cs probes (RELEASE.md:32-46; build/check-db-scripts.ps1:26-135; build/check-schema-versions.ps1:4-18) - Version stamp: Version.h (three defines), section_setup_64.iss, seven .csproj
<Version>;git grep <old-version>(RELEASE.md:48-50) - Build everything at the stamped version:
build.ps1 -Configuration Release,build-tools.ps1 -Configuration Release, ControlPaneldotnet publish,build-tests.ps1; confirm FileVersion on hMailServer.exe and publish\hMailCP.dll; regenerate the interop wrapper if the IDL changed (AFTER any interface-ordering fix); prove reproducibility by a secondbuild\build.ps1 -Configuration Release -Cleanand compare SHA-256; put the hash in the notes (RELEASE.md:51-78) 8b. Full regression suite on the assertion build first (build.ps1 -Configuration Release -Asserts), expecting no HM6364 line - a violation fails the test that provoked it; then rebuild plain Release before step 9 (RELEASE.md step 8b, added 5 Sep 2026) - Full regression suite on the stamped binary; any change afterwards voids the run; never abort (RELEASE.md:79-83)
- README/release notes: "Fixed" means reproduced-then-fixed or negative-control-tested; otherwise "hardened"/"instrumented"/"still open" (RELEASE.md:84-87,164-167)
- Installer: ISCC on hMailServer64.iss; never run it on the dev machine; validation is the
installer-smoke.ymlworkflow (RELEASE.md:88-90) - Commit as chrisholloway5 (no co-author trailers); master is protected so:
git push origin <branch>,gh pr create --base master --head <branch> --fill,gh pr merge --rebase(self-merge allowed, no reviewer required),git pull --ff-only origin master. Then an annotated SIGNED tag:git tag -s vX.Y.Z -m "hMailServer X.Y.Z",git -c gpg.ssh.allowedSignersFile=.github/allowed_signers verify-tag vX.Y.Z,git push origin vX.Y.Z. Signing is SSH (gpg.format ssh,user.signingkey= public key path); the key must be in.github/allowed_signers. Then publish as a DRAFT:gh release create vX.Y.Z <installer> --draft --prerelease --title "..." --notes-file <notes>,gh workflow run "SBOM" -f release_tag=vX.Y.Z,gh workflow run "Sign release artefacts" -f tag=vX.Y.Z(LAST),gh release view vX.Y.Z --json assets(expect installer + 2 SBOMs + bundles),gh release edit vX.Y.Z --draft=false(RELEASE.md:91-151). The installer asset must be named exactlyhMailServer-<tag without the leading v>-x64.exe(with its.cosign.bundlebeside it): the update checker in every running server builds that name from the tag and matches it exactly, and the signing workflow refuses a release that lacks it (RELEASE.md:159-167; sign-release.yml:139-160). v6.2.22-pre3 shippedhMailServer-6.2.22-x64.exeunder that tag, which is the case the check exists for. - Close the loop on every issue the release resolves or does not (RELEASE.md:152-153)
Mechanics that are facts rather than advice:
- Immutable releases are enabled: a published release refuses further asset uploads (HTTP 422); a tag that backed an immutable release can never back another, even after deletion - a broken release needs the next version number (source: RELEASE.md:124-151; sbom.yml:7-12; sign-release.yml:6-9)
- Draft releases deliver no
releaseevent, so both the SBOM and signing workflows MUST be dispatched by hand with the tag (source: RELEASE.md:141-147; sbom.yml:14-17; sign-release.yml:40-44) - Local git config on the maintainer's machine:
gpg.format ssh,user.signingkey C:/Users/chris/.ssh/id_ed25519.pub(source:git config --local, code) - Allowed signer: principal
christopher.j.holloway@outlook.com, key type ssh-ed25519 (source: .github/allowed_signers:11, code) - Standing rules: prefer two small releases over one large; a fix to a shared layer needs a dependents audit; the public record never overstates (source: RELEASE.md:155-167)
- The installer smoke test ran twice on 2026-09-04 (17:46 and 18:42 UTC), both success, the second at the v6.2.24 publish time (source:
gh run list --workflow=installer-smoke.yml, gh)
- Tag signature:
git -c gpg.ssh.allowedSignersFile=.github/allowed_signers verify-tag v6.2.24(source: SECURITY.md:86-92; .github/allowed_signers:5) - Asset signature:
cosign verify-blob --bundle hMailServer-x.y.z-x64.exe.cosign.bundle --certificate-identity-regexp '^https://github\.com/Progressiverobot/hmailserver/' --certificate-oidc-issuer https://token.actions.githubusercontent.com hMailServer-x.y.z-x64.exe(source: SECURITY.md:94-104; sign-release.yml:30-36) - Signing is keyless Sigstore via GitHub OIDC, recorded in Rekor; no long-lived key exists (source: sign-release.yml:18-22; GOVERNANCE.md:111,123-125)
- Reproducible binary hash for v6.2.28:
9E89C1E3ABF4DD36560B0B5F3515BDA3DAB8B96F00EF35DA5376A9B60176BD15(hMailServer.exe 6.2.28.38) with the v145 toolset and the README library layout; the v6.2.27 hash was8CD745C49657A2E02989A8A86E9290C0AA49D317466B860C3749C757C129410F(6.2.27.37, identical across three clean Release builds) and the v6.2.24 hash64406163b1a3a8a865e34d74883b5e2a05a5a1c476b500b26745cde67d8a989b(source: release notes' verification sections, gh) - The installer is Authenticode-signed from 6.3.1 (11 September 2026) with Azure Artifact Signing, countersigned; SmartScreen still warns on reputation and Sigstore remains the provenance check for every asset; releases before 6.3.1 are unsigned and immutable (source: v6.3.1 body; sign-release.yml authenticode job)
- SBOMs: SPDX 2.3 JSON and CycloneDX JSON, produced by Syft plus the native-dependency merge (source: sbom.yml:55-85; build/merge-native-dependencies-into-sbom.ps1:4-9)
- Supported: 6.2.x yes; < 6.2 no (source: .github/SECURITY.md:5-8)
- Report privately via https://github.com/Progressiverobot/hmailserver/security/advisories/new; never a public issue/discussion/PR or the forum; fallback: a bare issue asking for a private channel (source: SECURITY.md:12-22)
- Targets: acknowledgement 5 working days; initial assessment 10 working days; fix for a confirmed vulnerability 90 days from acknowledgement; single maintainer, not contractual (source: SECURITY.md:26-34)
- Coordinated disclosure on a 90-day timetable; advisory published at fix or 90 days, whichever first; reporter credited unless they decline; no NDA, no bounties; CVE requested through GitHub (source: SECURITY.md:36-47)
- In scope: RCE/memory corruption in protocol handlers; auth/authz bypass; TLS/crypto (DANE, MTA-STS, DKIM/ARC, certificates); SQL injection; privilege escalation via the service or COM API (source: SECURITY.md:49-58)
- Out of scope: findings requiring an existing administrator account; missing hardening on a listener deliberately exposed without TLS; scanner output with no demonstrated impact (banners, TLS grades); third-party dependency vulnerabilities with no path from hMailServer (source: SECURITY.md:60-75)
- Supply chain: SBOM (SPDX + CycloneDX) covering .NET and native deps on every release; committed binaries inventoried, checksummed and verified on every build (source: SECURITY.md:77-82)
- Issue template routes "Security vulnerability" to the advisory URL (source: .github/ISSUE_TEMPLATE/config.yml:3-5)
- Single-maintainer project stewarded by Progressive Robot Ltd; Christopher Holloway (@chrisholloway5) holds every role; decisions made in the open on the issue tracker (source: GOVERNANCE.md:13-15,29)
- Maintainer duties: accepting changes, releasing per RELEASE.md (full suite on the exact shipped binary, signing every asset), security response per SECURITY.md, direction via Roadmap.md, infrastructure/credentials (source: GOVERNANCE.md:31-47)
- Contributor: anyone who opens a PR; follows CONTRIBUTING.md; no CLA (source: GOVERNANCE.md:49-57)
- Reporter: SUPPORT.md for defects, SECURITY.md for security; credited unless they decline (source: GOVERNANCE.md:59-66)
- Decisions: maintainer decides with reasons recorded in the PR/issue/release notes; disagreements on the issue, reopening with a reproduction welcome; scope test is "does it serve people running this as a mail server in production"; compatibility with existing deployments is a standing constraint; security decisions are the maintainer's alone (source: GOVERNANCE.md:71-89)
- Becoming a maintainer: demonstrated sustained judgement plus willingness to take release and security duties; say so on an issue (source: GOVERNANCE.md:94-100)
- Critical assets: GitHub repo admin; release signing path (Sigstore keyless, no private key held); "code-signing material - signing the Windows installer"; build environment recipe (VS 2026/v145 + hMailServerLibs); test environment recipe (source: GOVERNANCE.md:108-114). NOTE: the installer is not Authenticode-signed today (SECURITY.md:107), so the "code-signing material" row describes an asset the project does not currently hold - see section 17.
- Continuity: knowledge bus factor 1; access continuity arranged (credentials in a managed arrangement a trusted person can reach); mitigations: everything scripted and committed, keyless signing, AGPLv3 permits a fork (source: GOVERNANCE.md:130-151)
- Changing GOVERNANCE.md: by pull request, maintainer decides with a reason (source: GOVERNANCE.md:156-158)
- Regulatory position: "out of scope as a manufacturer" under the EU Cyber Resilience Act and revised Product Liability Directive, reviewed 12 August 2026, self-assessment not legal advice; premises: AGPLv3, no paid edition/support/hosting, no telemetry, one individual (source: hmailserver/docs/RegulatoryScope.md:1-26, doc)
- Scorecard is measured and published to the OpenSSF API (
publish_results: true, since 5 September 2026); Branch-Protection and Code-Review checks are expected to fail on a single-maintainer repo (source: scorecard.yml:9-15,74-86)
Claims (source: ASSURANCE-CASE.md section 2):
- C1 unauthenticated peer cannot execute code/corrupt memory/crash via mail protocols
- C2 unauthenticated peer cannot read/modify/delete account mail or authenticate as one
- C3 credentials at rest not practically recoverable from a stolen database
- C4 credentials in transit not exposed and never sent to an unverified peer
- C5 untrusted content cannot alter a query, filesystem path or third-party protocol exchange
- C6 an authenticated user cannot reach another user's mail or gain admin capability
- C7 a user can verify the downloaded software is what the project published
Threat model actors A1-A6 (internet stranger, sending MTA, network attacker, authenticated user, malicious upstream DNS/TLSA/MTA, local attacker); administrators are explicitly NOT adversaries (source: ASSURANCE-CASE.md section 3). Trust boundaries B1-B6: TCP/TLS termination, protocol grammar, authentication, parameterised query, external process/filesystem, COM management plane (source: section 4).
Backing, as claimed and as checked in code:
- Single management seam: everything goes through
Server/COM/(source: ASSURANCE-CASE.md section 5; ARCHITECTURE.md "Patterns that matter", doc) - Fail-safe hash default:
PreferredHashAlgorithmread from[Settings]with default 4 (PBKDF2); values 0/1/2 are logged and replaced with 4; 3 = SHA256, 5 = Argon2id (source: hmailserver/source/Server/Common/Application/IniFileSettings.cpp:171,187, code) - Minimum acceptable scheme:
MinimumAcceptedHashAlgorithm, default 0 (source: IniFileSettings.cpp:198; IniFileSettings.h:152, code) - Pepper:
PasswordPepperstring setting, default empty (source: IniFileSettings.cpp:203; IniFileSettings.h:153, code) - Argon2id via OpenSSL EVP_KDF in
DeriveArgon2id(source: hmailserver/source/Server/Common/Util/Hashing/HashCreator.cpp:61-65, code) - Outbound TLS verification:
verify_peer | verify_fail_if_no_peer_cert(source: hmailserver/source/Server/Common/TCPIP/TCPConnection.cpp:556,602,609, code); DANE and DNSSEC inCommon/TCPIP/DaneVerifier.*andDnssecResolver.*;SslContextInitializer.*present (source:ls Common/TCPIP, code) - CSPRNG:
RAND_bytesappears in 37 server source files; the only remainingrand()is the MIME part-boundary string at Common/Mime/Mime.cpp:807, matching the document's stated exception (code) - SCRAM-SHA-256 referenced in TCPConnection.cpp/.h and PersistentAccount.h; TOTP in Common/BO/Account.cpp/.h (code)
- Session ceiling:
GetClientSessionCeiling()(source: IniFileSettings.h:209, code);DatabaseUnavailableMarker.cppexists under Common/SQL and is used by DatabaseConnectionManager.cpp, BackupExecuter.cpp, IniFileSettings.cpp (code) - Compiler hygiene: /WX, CFG, /GS-DEP-ASLR (see section 4; PE header verified)
- SMTP smuggling rule (CVE-2023-51764): bare-LF accepted only with "Allow incorrect line endings", and only at buffer end (source: ASSURANCE-CASE.md section 6, doc - not re-verified here; protocol readers should confirm the setting name)
- Static analysis: "CodeQL runs on every push and pull request" is exactly true for C# only. The C++ job "Analyze (c-cpp)" runs on every push to master, weekly and on dispatch, but not on pull requests (codeql.yml:163); since it moved to the hosted
windows-2025-vs2026image on 5 September 2026 it completes - e.g. run 34179895726 (push, 2026-09-08) "Analyze (c-cpp) (windows-2025-vs2026): success" (source:gh run view <id> --json jobs, gh; Roadmap.md:1368). Before that, every scheduled run since the job was added on 2026-08-13 had been cancelled waiting for a self-hosted runner that was never registered. - Fuzzing: libFuzzer harnesses under
fuzz/for MIME only; HTML/iCalendar/vCard not done; the corpus is generated bymake-corpus.ps1, not committed (source: fuzz/README.md:4-6,47; hmailserver/docs/Fuzzing.md:10-13). The /EHa +catch (...)crash-oracle problem is documented (Fuzzing.md "Why this waited on the crash oracle"). - Supply chain (C7): sign-release.yml, verify-binary-provenance.yml, sbom.yml, Dependabot, dependency-review (see section 8)
- Evidence table names:
fuzz/, CodeQL workflow,/WXin hMailServer.vcxproj, regression suite;Server/Common/BO/;HashCreator.cpp,IniFileSettings.cpp;TCPConnection.cpp,SslContextInitializer.cpp; CONTRIBUTING.md SQL rule;.github/workflows/sign-release.yml,verify-binary-provenance.yml,sbom.yml(source: ASSURANCE-CASE.md section 7) - Residual risk, stated: memory safety mitigated not guaranteed; native statement coverage not measured (only the .NET Control Panel is); reproducibility shown on one toolchain only; CFG is a mitigation not a boundary; bus factor 1; administrators inside the boundary; operator-chosen weakening (plaintext listeners, legacy hashes) is permitted with a warning (source: ASSURANCE-CASE.md section 8)
- Review cadence: revisit on any threat-model change and at least yearly (source: ASSURANCE-CASE.md "Reviewing this document")
- Project licence: GNU Affero General Public License v3, 19 November 2007 text in
LICENSE; SPDX identifier used throughout isAGPL-3.0-or-later(source: LICENSE:1-2; every build/*.ps1 header line 2; dco.yml:4, code) - README states AGPLv3 and points to
hmailserver/docs/Licensesfor third-party texts (source: README.md:568-571) - Copyright line used on source files: "Copyright (c) 2026 Christopher Holloway / Progressive Robot Ltd and the hMailServer contributors" (source: build/build.ps1:1 and all others, code)
- Header enforcement:
build/add-license-headers.py --checkin the "SPDX identifier on every source file" required check (source: style.yml:43-55) - Local nit: run today, the check flags
hmailserver\source\Server\hMailServer\hMailServer.h(MIDL output) - that file is gitignored (.gitignore:24) so CI never sees it, but the script's SKIP_FILES does not list it (code) - Third-party licence texts held: 7-Zip, Boost, Fat Cow Icons, MIME Message encoder analyzer, Microsoft SQL Server Compact Edition, OpenSSL, PostgreSQL interface, RMSPF, String library, ZLib, plus
License list.ods(source:ls hmailserver/docs/Licenses, code) - Known licence gap: no LGPL-2.1 text for MariaDB Connector/C although twenty committed files and the installer include it;
msado28*.tlbredistribution terms not established (source: hmailserver/docs/ThirdPartyBinaries.md "Not yet done", doc; Licenses dir confirms absence, code)
- Out-of-tree (built by the developer or by CI's native-dependencies action, referenced via hMailServerLibs): OpenSSL 4.0.2, Boost 1.92.0, PostgreSQL 18.3 libpq (source: hMailServer.vcxproj:76; README.md:287-336; build/Get-LibraryVersions.ps1)
- In-tree vendored source (not a committed binary, so outside the manifest): zlib 1.3.1 under
hmailserver/source/Server/zlibwith its LICENSE, compiled into hMailServer.exe for IMAP COMPRESS=DEFLATE (new in 6.2.28);build/native-dependencies.ps1lists only openssl/boost/postgresql, so zlib is not yet named in the SBOM (source: hmailserver/source/Server/zlib/zlib.h:40; hMailServer.vcxproj; build/native-dependencies.ps1, code) - Manifest
hmailserver/docs/third-party-binaries.json: schemahmailserver-third-party-binaries/1, 40 artifacts, fields path/sha256/size/component/version/publisher/license/upstream/authenticode/authenticode_signer/disposition/used_by/why (source: JSON parse, code) - Dispositions: retain 13, retain-review 13, remove-duplicate 10, remove-unused 3, retain-generated 1 (source: JSON parse, code; matches ThirdPartyBinaries.md "short version" table)
- Authenticode: 12 Valid (10 MSVC runtime signed by "Microsoft Windows Software Compatibility Publisher", 2 SQL CE MSIs by "Microsoft Corporation"), 28 NotSigned (source: JSON parse; ThirdPartyBinaries.md "Authenticode")
- Components: MariaDB Connector/C 3.4.9 (20 files: 10 under
libraries/mariadb-connector-c-3.4.9/, 10 byte-identical duplicates underinstallation/Extras/), MSVC v145 runtime 14.51.36231.0 (10,installation/Microsoft.VC145.CRT/), ADO 2.8 type libraries (2,libraries/msado28/, PE images despite .tlb), SQL Server Compact 4.0 SP1 x64 MSI (Microsoft withdrew the download; this copy is the archive of record), SQL CE x86 MSI (unused), 7za.exe 19.00 (upstream 26.02; refresh candidate), ISC.dll (unattributed, exports CheckPorts(), used by the installer - "should not survive to the next release"), isxdl.dll (declared, never called), atl70.dll (VS .NET 2003 ATL, vestigial), dnsapi.dll (Windows 2000, never loaded), Interop.hMailServer.dll (ours, AGPL) (source: ThirdPartyBinaries.md inventory tables; JSON component counts, code) - Policy: a binary may be committed only if listed in the manifest; changing one means changing its entry in the same commit; prefer not committing > vendor-signed original > hash+URL; unattributed binaries not acceptable long-term (source: ThirdPartyBinaries.md "Policy")
- Update procedure: change file, update
sha256/size/version/upstream/authenticode((Get-FileHash <path> -Algorithm SHA256).Hash.ToLower()), update the doc row, push (source: ThirdPartyBinaries.md "Updating the manifest") - Scorecard
Binary-Artifactsannotation deliberately NOT added until the 13 remove-* entries are gone (source: ThirdPartyBinaries.md "Relationship to OpenSSF Scorecard") - CI does not re-verify Authenticode (Linux runner) (source: ThirdPartyBinaries.md "Not yet done"; verify-binary-provenance.yml:29-33)
-
libraries/also contains the library build scriptsbuild-openssl.ps1,build-boost.ps1,build-pgsql.ps1and their sharedbuild-common.ps1, plusasio-overrides,fat_cow_icons,mssqlce3.5, and licence .rtf copies; its README.md still reads "hmailserver-dependencies-v1 ... This repository contains hMailServer external dependencies" (stale text from the separate upstream repo) (source:ls libraries; libraries/README.md:1-4, code) - MariaDB Connector/C is loaded at runtime from beside the exe (
libmysql.dll) with plugins viaMYSQL_PLUGIN_DIR; supports MySQL 8caching_sha2_password, MariaDBed25519/gssapi(source: ThirdPartyBinaries.md "Required in the tree"; README.md:101) - Interop wrapper regeneration documented in
hmailserver/source/Tools/Interop/README.md(see section 3)
-
Find-MsBuild.ps1- shared vswhere-based MSBuild locator (dot-sourced by the build scripts) -
Get-LibraryVersions.ps1- report the OpenSSL/Boost/PostgreSQL versions the project is pinned to, parsed from hMailServer.vcxproj (openssl=4.0.2,boost=1.92.0,postgresql=18.3plus the*_dirfolder names); CI uses it for the library cache keys and DLL paths -
add-license-headers.py- adds a copyright line + SPDX identifier to every source file lacking one;--checkreports and exits non-zero; handles BOM, CRLF/LF, shebangs, PowerShell help -
analyze.ps1- the static-analysis build: Release x64 rebuilt from scratch with MSVC/analyze, findings summarised by code and file intologs\analyze-warnings.txt(replaces the Release binaries; rebuild before a gate) -
build.ps1- MSBuild the server solution (x64, build events off;-Configuration,-Clean) -
build-tests.ps1- restore the test packages via the parent test solution, then MSBuild RegressionTests.sln (x64) -
build-tools.ps1-dotnet publishthe five setup/migration tools into theirpublish\folders (not the Control Panel) -
capture-cp.ps1- screenshot the running hMailCP window, optionally navigating via UI Automation (-Out,-Nav,-Launch) -
capture-dialog.ps1- open the Domain Properties dialog in the running hMailCP and screenshot it -
check-authz-choke-point.py- fail if any file other than ACLManager and its listed callers namesGetPermissionForFolder(,GetUseIMAPACLorGetAclEnforcementEnabled: every folder-access decision stays ACLManager's -
check-catalogues.py- read each translation catalogue against the English: server literals (log stage names, INI/setting names, INBOX, typed syntax) preserved, page references use the page's translated title, every number kept -
check-db-scripts.ps1- build a throwaway SQL CE database from CreateTablesMSSQL.sql and apply every upgrade script using SQLScriptParser's rules -
check-ini-coverage.py- every[Settings]keyIniFileSettingsreads is named somewhere in the Control Panel (with an EXEMPT list) and is read throughIniFileSettingsso the database mirror sees it -
check-localisation.py- the generated English catalogueStrings.resxmatches theL()/F()/N()/{loc:L}marks (--writeregenerates it); every language keeps placeholders and Alt keys; the 17 languages inCOMPLETEtranslate every key; files inLOCALISEDcarry no unmarked caption -
check-mnemonics.py- every static Control Panel caption (XAML and code-built) carries an Alt-key mnemonic and no two on one view or method share one -
check-roadmap.ps1- reconcile Roadmap.md tick boxes against per-section counts and the contents table; exits non-zero on drift -
check-schema-versions.ps1- prove the schema upgrade chain is contiguous, forward-only and complete for every backend (pwsh 7) -
find-stale-roadmap-rows.py- flag not-started roadmap rows that name symbols present in the tree (advisory, not a gate) -
generate-public-suffix-list.ps1- regenerateCommon/AntiSpam/DMARC/PublicSuffixListData.hfrom the Public Suffix List (-ListFilefor a reproducible local copy) -
generate-settings-index.ps1- regenerate the Control Panel's Ctrl+K settings search indexSettingsSearchIndex.g.cs(CI verifies it is up to date) -
get-dotnet-runtime.ps1- download the .NET Desktop Runtime installer the hMailServer installer bundles (-Channel 10.0) -
hmconfig.ps1- export/diff/apply hMailServer configuration as JSON over the COM API;applyis a dry run without-Force, deletions need-AllowDeletetoo; passwords never exported -
make-app-icon.ps1- generate the Control Panel .ico (256/64/32/16 px) -
make-hmailserver-writable.ps1- grant Everyone Modify on the hMailServer install folders (elevates; test machines only) -
make-installer-art.ps1- generate the Inno Setup wizard bitmaps (164x314 and 55x55) -
merge-native-dependencies-into-sbom.ps1- add OpenSSL/Boost/libpq to a Syft SBOM (SPDX 2.3 or CycloneDX) in place, idempotent by PURL -
native-dependencies.ps1- emit the native dependencies as JSON, versions parsed from hMailServer.vcxproj include paths -
post-build.ps1- elevated wrapper for post-build.bat: copy runtime DLLs and the .tlb, register the COM server/service -
preflight-tests.ps1- verify the machine is in the known-good state for the regression suite;-Cleanremoves a stale ERROR log -
regenerate-interop.ps1- TlbImp the Release type library into Interop.hMailServer.dll and update its manifest hash/size -
register-com.ps1- elevated re-registration of the type library and interfaces (needed only when the IDL adds a NEW interface) -
run-tests.ps1- run the NUnit regression suite against the live service (-StopOnError,-Where) -
upgrade-test-database.ps1- apply pending schema upgrade scripts to the bench database through the running service's COM API (source: header comments of each file under build/, code)
- RELEASE.md line 59 and hmailserver/source/Tools/Interop/README.md line 15 contain a raw carriage-return byte where a backslash should be: the bytes are
build<CR>egenerate-interop.ps1, and RELEASE.md line 60 hashmailserver\docs<TAB>hird-party-binaries.jsonwith a raw TAB.grep -rF 'build\regenerate-interop' --include=*.mdfinds nothing. The intended text isbuild\regenerate-interop.ps1andhmailserver\docs\third-party-binaries.json(source: byte inspection of both files, code) - README.md:110 says "Schema | Database version 6027"; the code requires 6031 (Constants.h:173)
- Dated test-count comment: run-tests.ps1:9 names "1361" and adds "(the count then; over 2,000 now)"; the actual
[Test]count is 2,127 at v6.2.28 and the v6.2.28 gate was 2,127 tests, 2,119 passed, 8 skipped (the old ci.yml and server-build.yml comments have been removed) - GOVERNANCE.md:112 lists "Code-signing material - Signing the Windows installer" as a critical asset; since 6.3.1 that is the Azure Artifact Signing account, its identity validation and the app registration CI signs through, not a certificate file (there is none to hold)
- ASSURANCE-CASE.md section 6 says "CodeQL runs on every push and pull request"; codeql.yml skips the C++ job on pull requests (it runs on push to master, weekly and on dispatch, and completes on the hosted image since 5 September 2026)
- ASSURANCE-CASE.md section 6 says
/GS,/NXCOMPAT,/DYNAMICBASEare "active"; the vcxproj does not set them (MSVC defaults). The shipped binary does have DEP/ASLR/HEVA/CFG on and a load-config directory, so the claim is true in effect but not project-enforced - CONTRIBUTING.md:46-48 says a PR whose commits lack the trailer "fails the DCO check"; the check is skipped for OWNER/MEMBER/dependabot authors and is not a required status check, so it cannot block a merge on its own (dco.yml:39-42; ruleset)
- RELEASE.md:76 cites "Windows SDK 10.0.26100" as part of the reproducibility toolchain; the project pins
WindowsTargetPlatformVersionto10.0(latest installed), so the SDK is not fixed by the source - ASSURANCE-CASE.md section 6 describes the fuzz suite as having "a corpus, dictionaries and a regression directory"; fuzz/README.md:47 says
corpus\is generated, not committed (one dictionary file,dict/mime.dict) - ThirdPartyBinaries.md's "Twenty MariaDB Connector/C DLLs" and "40 committed binaries" both agree with the JSON manifest (20 MariaDB entries, 40 artifacts) - no contradiction, recorded as checked
- README.md:180 requires "An installed version of hMailServer 5.7 or later" to build - the regression environment doc requires the service to run from the repo build, NOT an installed copy (RegressionEnvironment.md:35-41)
- Whether the v6.2.24 installer is (un)signed with Authenticode was not checked against the asset itself; the statement is from SECURITY.md and sign-release.yml
- The SMTP bare-LF / "Allow incorrect line endings" setting name and behaviour (ASSURANCE-CASE.md section 6) - not grepped here; belongs to the SMTP reader
- Whether the OpenSSF Best Practices "Passing 100%" also covers Silver/Gold criteria - the page reports Passing only
- Why the three scheduled C++ CodeQL runs were cancelled (runner offline vs manual) - only the outcome was read
- Whether
libraries/mssqlce3.5is used by anything (not referenced in the manifest doc's inventory) - The Roadmap.md item total (RELEASE.md:31 and check-roadmap.ps1 say "750"; not counted here)
- Whether a second person currently holds any repository rights (GOVERNANCE.md says no; not checked via API)
hMailServer 6.3.3, the latest release (schema 6040) · pages also describe the tree after 6.3.3 (schema 6045), not yet released, and say so where they do · AGPL-3.0-or-later · Repository · Report a documentation error
Hmail Server — full index
Start here
1. Install and run
- Before You Install
- Installing hMailServer
- Installing on Linux
- Running in a Container
- The Control Panel
- Your First Domain and Mailbox
- Connecting a Mail Client
- DNS for Your Domain
2. Secure it
3. Operate it
- Monitoring and Health
- Backup and Restore
- Troubleshooting
- Diagnosing Stalled Mail
- Relocating an Installation
- Upgrading hMailServer
- Upgrading Guide
- Migrating the Database Backend
- High Availability Runbook
- Warm Standby
- Runbooks Digest
4. Extend it
- Rules and Sieve
- Aliases Lists and Public Folders
- Routes and Relays
- The COM API and Scripting
- The REST API
- Command Line
- APIs Reference
5. Contribute to it
- Project Handbook
- Architecture
- Contributing
- Release Process
- Governance
- Assurance Case
- Regression Test Environment
- Fuzzing
- Regulatory Scope
- Third-Party Binaries
Look it up — from any journey