Skip to content

Regulatory Scope

Christopher Holloway edited this page Oct 21, 2026 · 21 revisions

Regulatory scope determination

Source of truth: hmailserver/docs/RegulatoryScope.md, kept in the repository and copied here. Re-copied from master 92b8f9f63 on 26 September 2026, and brought up the same day to the document as the tag v6.3.4 (51e2dbda0), the release, has it, which has caught up with the five things this note called out of date on 24 September - the Authenticode signing, where the releases are, the committed binaries, what runs on GitLab and, last, what the release half of its list depends on; re-copied on 5 October 2026 from the document as the tag v6.3.6 (e3c448aa6) has it (RegulatoryScope.md at v6.3.6): the GitLab release jobs that replace the GitHub workflows made 6.3.5 on 29 September 2026, and the live update trusts the path the project began at and the group's it moved to that day; and re-copied on 18 October 2026 from the document as the tag v6.3.7 (31d656c0c), the release, tagged and published on 17 October 2026, has it (RegulatoryScope.md at v6.3.7): the installer's fetched inputs come from the project's build-inputs-1 and build-inputs-2 releases, or from the publisher. The GitHub workflows it names are in the git history at v6.3.3. The update feed a server built after 6.3.3 reads is https://updates.progressiverobot.com, served by GitLab Pages. The dates, the decision tree, the Annex I table and the review triggers are this wiki's own additions. Re-copied on 19 October 2026 from the document as master has it from batch49, f14412d39 (RegulatoryScope.md at f14412d39), in which 6.3.7, the latest release, is reflected as at the tag; what it changes since the tag, most of it on the project's copy on GitHub since 18 October 2026: the releases are on GitLab, which is canonical, and copied to https://github.com/RainbowWizard-coder/hMailServer with the same files byte for byte; GitHub's own CodeQL default setup analyses the code there, and GitHub Actions runs one workflow of the project's, OpenSSF Scorecard's, which signs and publishes nothing of a release; the old release workflows ran once there on 18 October 2026 and have been disabled since; and the one signer a server up to 6.3.3 trusts is named as the GitHub release workflow of the repository under the project's former account, Progressiverobot. Re-copied on 20 October 2026 from the document as master has it from batch50, 0c0b6bae7 (RegulatoryScope.md at 0c0b6bae7), which changes what it says the releases carry: the list under Who is asking says that every release up to 6.3.3 whose files GitLab has is re-published there, 6.2.0 and 6.0.0-B4 being notes-only; What we do anyway says that SPDX and CycloneDX SBOMs are attached to every release from 6.2.3, the five earlier releases that carry an installer having a CycloneDX SBOM of it alone, made afterwards, that the release assets from 6.2.19 to 6.3.3 are signed, but for the two SBOMs of 6.2.22-pre3, and that the installers of the releases before 6.3.1 stay without an Authenticode signature because the releases up to 6.3.3 are published with their original files, byte for byte, on GitLab and in its copy on GitHub, where it gave a published release's immutability as the reason; and its account of the one workflow GitHub Actions runs says the same of the releases up to 6.3.3 whose files GitLab has. Re-copied on 21 October 2026 from the document as master has it from batch51, 5e49abf06 (RegulatoryScope.md at 5e49abf06), which changes it in two places, both under What we do anyway: the item on the scans says that CodeQL has analysed the code of the repository on GitHub since 18 October 2026, GitHub's default setup at first and then the workflow .github/workflows/codeql.yml in its place, and that GitHub Actions runs two workflows of the project's there, that one and .github/workflows/scorecard.yml, where it said that the default setup was GitHub's, not a workflow of the project's, and that Scorecard's was the one workflow; and the paragraph on the releases on GitHub says that the two workflows, Scorecard's and CodeQL's, sign and publish nothing of a release. The document's links to the repository's other documents point at them as 5e49abf06 has them, or at this wiki's copy where there is one.

Status: out of scope as a manufacturer. Reviewed 12 August 2026.

This is a dated, reviewable position on whether two pieces of EU legislation — the Cyber Resilience Act and the revised Product Liability Directive — place obligations on this project. It exists because both turn on how the software is supplied rather than what it does, so the answer can change without a line of code changing, and because the answer is much cheaper to write down now than to reconstruct under pressure later.

It is a self-assessment by the maintainer, not legal advice. Anyone relying on it commercially should take their own.

Who is asking

This fork is distributed as follows, and every conclusion below depends on these facts staying true:

  • AGPLv3, source public, no paid edition, no paid support, no hosted service.
  • Released as an installer and source on GitLab (https://gitlab.com/hmailserver/hmailserver), which is canonical, and on GitHub, at https://github.com/RainbowWizard-coder/hMailServer under the account RainbowWizard-coder since 18 October 2026, where every release from 6.0.0-B1 to 6.3.7 is a copy of GitLab's, with the same files byte for byte; a release is built, signed and published on GitLab first and then copied there. The project was on GitHub before, under the account Progressiverobot, until GitHub suspended that account on 18 September 2026; every release up to 6.3.3 whose files GitLab has is re-published there, byte for byte, with its original signatures (6.2.0 and 6.0.0-B4 are notes-only). No charge, no licence key, no mandatory registration, no telemetry. Where the project is hosted is not one of the review triggers below, and neither the move nor the return changed anything else on this list.
  • Maintained by one individual, not a company or foundation.
  • Donations, sponsorship and paid consulting: none currently, and see the triggers below before that changes.

Cyber Resilience Act — Regulation (EU) 2024/2847

In force 10 December 2024. Article 14 reporting obligations apply from 11 September 2026. Everything else — Annex I essential requirements, conformity assessment, CE marking, technical documentation, declaration of conformity — applies from 11 December 2027.

Two independent questions decide whether it reaches this project.

1. Is it made available in the course of a commercial activity? That is the test, and free of charge is not the test. Recital 18 says how development is financed is not to be taken into account. The Commission's guidance under Article 26 (document C(2026) 5252, approved 27 July 2026) confirms that freely available open-source software is generally outside scope, and that voluntary donations, sponsorship, public funding, and paid consulting or training do not by themselves make a project commercial.

Commerciality would arrive with: selling the software; shipping a paid "pro" edition; monetising a service built on it; requiring personal data beyond what security or interoperability needs; or making donations effectively mandatory for access or updates.

2. Could it be an "open-source software steward" under Article 24? No — a steward must be a legal person. A sole individual maintainer is neither a manufacturer (while non-commercial) nor eligible to be a steward.

Conclusion: out of scope as manufacturer, ineligible as steward.

What changes it, and how much. The moment there is a paid tier, a hosted edition or a commercial licence exception, the whole product is in scope — and because this fork substantially modifies upstream hMailServer, this fork is the manufacturer of record, not the upstream project. Two consequences worth knowing before that decision rather than after:

  • A UK-based commercial manufacturer also needs an EU authorised representative (Article 18) — a real, recurring cost.
  • Annex I would then require, in code as well as paper: secure-by-default configuration, no known exploitable vulnerabilities at release, security update distribution with integrity verification, an SBOM, coordinated vulnerability disclosure, and a defined support period.

Product Liability Directive — (EU) 2024/2853

Transposition deadline 9 December 2026, applying to products placed on the market from that date.

Software is now unambiguously a "product", including a standalone download. A product can be defective because of a cybersecurity vulnerability, or because the manufacturer failed to supply security updates — and liability under the PLD cannot be excluded or limited by contract. The AGPLv3 warranty disclaimer does not help here; that is the point of the provision.

The exemption is the same shape as the CRA's: software supplied outside a commercial activity.

Conclusion: out of scope, on the same basis, and it raises the stakes on the CRA answer considerably. Monetising would attach strict liability for security defects across the EU from December 2026 — a full year before CRA conformity obligations bite. That ordering is worth remembering: the liability arrives first.

The dates, in order

Both instruments phase in, and they do not phase in together. The ordering matters more than any single date: liability arrives a full year before conformity obligations do.

flowchart LR
    D1["10 Dec 2024<br/>CRA in force"] --> D2["11 Sep 2026<br/>CRA Article 14<br/>reporting obligations apply"]
    D2 --> D3["9 Dec 2026<br/>PLD transposition deadline -<br/>applies to products placed on<br/>the market from this date"]
    D3 --> D4["11 Dec 2027<br/>CRA Annex I essential requirements,<br/>conformity assessment, CE marking,<br/>technical documentation,<br/>declaration of conformity"]
Loading

None of those dates changes this project's position while the distribution facts under Who is asking hold. They are here so that the consequences of a change are visible before the change is made rather than after.

The determination as a decision tree

Two independent questions decide whether the CRA reaches this project. The second only matters if the first is answered "not commercial".

flowchart TD
    START["Is the CRA engaged<br/>for this project?"] --> Q1{"Made available in the course<br/>of a COMMERCIAL ACTIVITY?<br/>Free of charge is NOT the test"}
    Q1 -- "yes" --> MANU["MANUFACTURER.<br/>The whole product is in scope"]
    Q1 -- "no" --> Q2{"Could it be an open-source<br/>software STEWARD under Article 24?"}
    Q2 -- "a steward must be a LEGAL PERSON;<br/>a sole individual maintainer is not" --> OUT["OUT OF SCOPE as manufacturer,<br/>INELIGIBLE as steward.<br/>Reviewed 12 August 2026"]
    MANU --> CONS["And this fork is the manufacturer<br/>of record, not upstream hMailServer,<br/>because it substantially modifies it"]
    CONS --> REQ["Then: an EU authorised representative<br/>for a UK-based manufacturer, Article 18 -<br/>plus Annex I in code as well as on paper"]
Loading

What "yes" to the first question looks like: selling the software; a paid "pro" edition; monetising a service built on it; requiring personal data beyond what security or interoperability needs; or making donations effectively mandatory for access or updates.

What "no" looks like, and it is broader than people expect: Recital 18 says how development is financed is not to be taken into account, and the Commission's guidance under Article 26 confirms that voluntary donations, sponsorship, public funding, and paid consulting or training do not by themselves make a project commercial.

What Annex I would then require, in code as well as paper: secure-by-default configuration, no known exploitable vulnerabilities at release, security update distribution with integrity verification, an SBOM, coordinated vulnerability disclosure, and a defined support period.

The PLD exemption is the same shape — software supplied outside a commercial activity — which is why one decision changes both answers at once, and why the AGPLv3 warranty disclaimer is not a fallback: liability under the PLD cannot be excluded or limited by contract, and that is the point of the provision.

Where each Annex I requirement already stands

If scope ever changed, this is what would already exist and what would not. It is also a fair summary of why the "What we do anyway" list is worth the effort.

Annex I theme, as summarised above Today Where
Secure-by-default configuration Largely met: TLS 1.2/1.3 only, outbound MTA-STS and DANE with DNSSEC on from the first start, PBKDF2 by default, every optional listener off until given a port; and since 6.3.4 a new installation's database is given a self-signed certificate, STARTTLS on 25, 587, 110 and 143 and TLS required for authentication on the Internet IP range, and on Windows the service runs as NT SERVICE\hMailServer rather than LocalSystem - an upgraded installation keeps what it had (SecureDefaults.md, ServiceAccount.md) Capabilities and Configuration
No known exploitable vulnerabilities at release A full regression gate on the exact shipped binary, an assertion build before it, a timed fuzz run, CodeQL while CI ran on GitHub, and cppcheck, clang-tidy, Semgrep and GitLab's SAST in GitLab CI, which since 26 September 2026 hold a release while they report a finding no baseline or written exception accepts (Security Policy, Before a release), and release notes that name unfixed issues rather than omitting them Release Process steps 8b, 8c, 9, 10
Security update distribution with integrity verification New in 6.2.28. The server checks the release feed, fetches a newer installer with its Sigstore bundle, verifies the bundle in-process against this project's release signers, and applies it inside a configured window after a backup. 6.3.4 carries no Sigstore bundle, so no server's live update installs it: it is installed by hand, and its download is checked against its SHA-256 sums file, signed with the release tags' SSH key Changes-Since-6210 section 4a
An SBOM SPDX and CycloneDX on every release from 6.2.3, with the native dependencies merged in — without which a CVE-feed check would conclude this server does not link OpenSSL - and from 6.3.4 a CycloneDX SBOM of its own beside every compiled file a release carries sbom.yml up to 6.3.3; build/asset-sbom.py and the linux-sbom job from 6.3.4
Coordinated vulnerability disclosure Published policy, private advisory route, and a machine-readable security.txt (RFC 9116) served at /.well-known/security.txt Security Policy
A defined support period Defined for the 6.3 line: security fixes until 30 September 2027; before that date the maintainers say in Security Policy whether support continues, and if nothing is written the 6.3 line is not supported from 1 October 2027; nothing below 6.3 is supported Security Policy, Supported versions and What is supported, and for how long
Authenticode signing Met since 6.3.1: the Windows installer is signed with Azure Artifact Signing, 6.3.4 by hand. Cosign and Authenticode are complementary, not alternatives: SmartScreen and UAC know nothing about Sigstore Release Process, Authenticode

Review triggers, and what each one would change

Trigger What changes
Any paid offering — licence, support, hosting, a "pro" edition, a commercial licence exception Commercial activity. Manufacturer under the CRA and in scope for the PLD, with strict liability for security defects across the EU
Donations or sponsorship become a condition of access or updates The same, by the "effectively mandatory" test
The maintainer incorporates, or maintenance moves to a company or foundation Steward status under Article 24 becomes possible — a legal person can be one — which changes the analysis rather than simply worsening it
Distribution starts collecting personal data beyond security and interoperability purposes Counts towards commerciality
Further Commission Article 26 guidance, or harmonised CRA standards, change the open-source treatment The determination is re-done with a new date regardless of anything this project did

Things that do not reach this project

Recorded so the question does not get re-opened each time it comes up.

  • NIS2 — addresses operators of essential and important entities, not software vendors. It shapes what customers will ask for (logging, incident detection, message trace), which is a product argument, not a compliance one.
  • GDPR / UK GDPR — this project is neither controller nor processor; the operator of a given installation is. That is precisely why per-account export, erasure reaching both the message store and the logs, and log retention limits are worth building: to let operators meet their obligations. They are features, not compliance for us.
  • DORA — reaches financial entities and their critical ICT providers by contract. Not applicable to unpaid distribution.
  • eIDAS 2 / qualified electronic registered delivery — a different service category entirely. Not relevant, and not planned.

Review triggers

Re-do this determination, with a new date, when any of the following happens:

  1. Any paid offering appears — licence, support, hosting, a "pro" edition, or a commercial licence exception.
  2. Donations or sponsorship become a condition of access or updates.
  3. The maintainer incorporates, or maintenance moves to a company or foundation (which would make steward status possible, and change the analysis).
  4. Distribution starts collecting personal data beyond security and interoperability purposes.
  5. The Commission issues further Article 26 guidance, or harmonised standards under the CRA are published, that change the open-source treatment.

What we do anyway

Not because either instrument compels it, but because they are the right shape for a security-relevant product and they would be prerequisites if scope ever changed:

  • SPDX and CycloneDX SBOMs attached to every release from 6.2.3 (up to 6.3.3 by the GitHub workflow sbom.yml, in the git history at v6.3.3; on GitLab the linux-sbom job makes them), including the native dependencies — OpenSSL, Boost and libpq — that a source-tree scan does not see. The five releases before 6.2.3 that carry an installer have a CycloneDX SBOM of it alone, made afterwards from the installer itself (Security Policy, Supply chain). That matters for exactly the purpose an SBOM has: without them, anyone checking a release against a CVE feed would have concluded this server does not link OpenSSL.
  • No executable binary is committed to the repository. Forty were until 11 September 2026. The ones the build still needs are fetched at build time from the project's build-inputs-1 and build-inputs-2 releases, or from the publisher, and checked against a SHA-256, gathered from the build machine's Visual Studio and checked by version, copied from Windows itself, or generated from this repository's own IDL, and every one is inventoried with an upstream, a version, a licence and the reason the build needs it (third-party-binaries.json, explained in Third-Party Binaries). Until 18 September 2026 every push and pull request ran the GitHub workflow verify-binary-provenance.yml (in the git history at v6.3.3), which failed if a binary appeared that the inventory did not describe, or one it lists as fetched was committed after all. The SBOM answers "what does this link against"; this answers the separate question "what unreviewable files are in the source tree, and who made them".
  • The release assets from 6.2.19 to 6.3.3 signed - but for the two SBOMs of 6.2.22-pre3, which carry no bundle - with Sigstore cosign, keyless via OIDC, the signature recorded in the public Rekor transparency log and verified in the same job so a malformed bundle cannot reach a user (the GitHub workflow sign-release.yml, in the git history at v6.3.3). Keyless deliberately: for a single-maintainer project a long-lived signing key held in CI is itself the thing most worth stealing.
  • The Windows installer Authenticode-signed since 6.3.1 (11 September 2026), with Azure Artifact Signing against a certificate profile issued to Progressive Robot Ltd, by the authenticode job of the same workflow (Release Process, Authenticode). Cosign and Authenticode are complementary rather than alternatives — SmartScreen and the UAC prompt read Authenticode and know nothing about Sigstore. The Linux packages carry no Authenticode, and the installers of the releases before 6.3.1 stay without it: the releases up to 6.3.3 are published with their original files, byte for byte, on GitLab and in its copy on GitHub - 6.2.0 and 6.0.0-B4 with none, which only the suspended account, or someone's old download, has (Roadmap3.md, The files GitLab does not have).
  • A documented security policy and private disclosure route (Security Policy), plus a machine-readable security.txt (RFC 9116) served at /.well-known/security.txt by the web services listener. The same listener serves the other well-known paths this server answers: /.well-known/acme-challenge/, /.well-known/mta-sts.txt, /.well-known/caldav and /.well-known/carddav, and /.well-known/openpgpkey/ - the OpenPGP Web Key Directory, which publishes public keys only and is off until an administrator, a domain and an account each say otherwise (OpenPGP.md).
  • Static analysis with CodeQL, and OpenSSF Scorecard, on every push to master on GitHub until 18 September 2026; neither runs on GitLab. Since 25 September 2026 GitLab CI runs replacements for master, batch* branches and release tags, not yet blocking: cppcheck, clang-tidy and Semgrep, dependency scanning with Trivy and OSV, and a check of the repository settings Scorecard read (ContinuousIntegration.md). Since 18 October 2026 CodeQL analyses the code of the project's repository on GitHub, https://github.com/RainbowWizard-coder/hMailServer, on each push to master, on each pull request and weekly, and the maintainers read its findings, nothing more: GitHub's default setup at first, and then the workflow .github/workflows/codeql.yml in its place. GitHub Actions runs two workflows of the project's there, that one and .github/workflows/scorecard.yml, OpenSSF Scorecard over that copy. A full regression suite gating every release.
  • Release notes that name unfixed known issues rather than omitting them.
  • Security-update distribution with integrity verification, shipped in 6.2.28 (8 September 2026): the server can check the release feed, fetch a newer installer with its Sigstore bundle, verify the bundle in-process against the release signers compiled into it, and apply it inside a configured window after a backup. A server up to 6.3.3 trusts one signer, the GitHub release workflow of the repository under the project's former account, Progressiverobot; a server built after 6.3.3 trusts that workflow for the releases up to 6.3.3 and this project's GitLab CI pipeline for the later ones, at the path the project began at and at the group's it moved to on 29 September 2026 (SigstoreVerifier.cpp, The Update Feed). The Roadmap's Product Liability Directive row was closed on 7 September 2026 against this document's determination.

What the release half of this list now depends on: up to 6.3.3 the SBOMs, the Sigstore signatures, the Authenticode signature and the provenance check were all made by GitHub Actions workflows, the Azure identity that signs the installer was reached through GitHub Actions' secrets, and a server up to 6.3.3 accepts an update only when its Sigstore bundle names that workflow's GitHub identity. None of the workflows has run since GitHub suspended the project's account on 18 September 2026 but for two: sbom.yml and sign-release.yml, in the trees of the old tags, ran once on 18 October 2026 in the repository the project has had on GitHub again since that day, on the copies of the releases up to 6.2.22-pre6, what they wrote was undone, and both have been disabled there since (Assurance Case). The two workflows of the project's that GitHub Actions runs there, OpenSSF Scorecard's and CodeQL's, sign and publish nothing of a release: a release there is a copy of the one on GitLab, with the same files byte for byte, and a release is built, signed and published on GitLab first and then copied there. The releases up to 6.3.3 whose files GitLab has are on GitLab with their original signatures (6.2.0 and 6.0.0-B4 are notes-only); 6.3.4 was built and Authenticode-signed by hand and carries no Sigstore bundle or provenance; and the GitLab release jobs that replace the workflows made 6.3.5 on 29 September 2026, with its SBOMs, its Sigstore bundles and its Authenticode signature, the Azure identity reached through a federated credential for the tag and no secret (ContinuousIntegration.md). Moving the chain off a single forge is its own row in Roadmap2.md, The release chain off a single forge.

What in this document is checkable, and what is not

Worth separating, because the two halves have very different half-lives.

The determination — the scope analysis, the commerciality test, the steward question, the PLD reasoning — is a dated legal self-assessment. Nothing in the repository can confirm or refute it; it stands or falls on the legislation and on the distribution facts listed under "Who is asking", and it is re-done when one of the review triggers fires. Reviewed 12 August 2026.

The "What we do anyway" list is different: every item is a claim about this repository, and each one is verifiable. Re-checked 13 August 2026 against .github/workflows/sbom.yml (SPDX and CycloneDX, both attached on a release event, with build/merge-native-dependencies-into-sbom.ps1 adding OpenSSL, Boost and libpq), .github/workflows/sign-release.yml (cosign sign-blob over every asset, then verify-blob in the same job), .github/workflows/codeql.yml, .github/workflows/scorecard.yml, .github/workflows/verify-binary-provenance.yml (run against this tree: 40 manifest entries, 40 binaries found, 0 unlisted, every hash matching the bytes stored in git), .github/SECURITY.md, and WebServicesServer's /.well-known/security.txt handler. (Those paths are as they were that day: the workflows are in the git history at v6.3.3, and the policy is SECURITY.md at the repository root.)

Re-checked 25 September 2026, for the move off GitHub: no tracked file is a binary by the provenance workflow's own detector (its extension set, and its PE, ELF and OLE sniff over git ls-files); every one of the manifest's 35 entries is marked as not in git - 22 fetched, 10 gathered, 2 system, 1 generated - and none is tracked; the build-inputs-1 release is on GitLab with the three assets the manifest hashes; SECURITY.md is at the repository root, and the Policy: line of the served security.txt names it there on GitLab. The workflows named above are in the tree, and none of them runs on GitLab.

This half is the one to re-read before quoting the page. A signing line in it has been wrong twice for the same reason - a capability shipped and the paragraph saying it had not was never revisited - the second time the Authenticode paragraph, which called the signing outstanding for two weeks after 6.3.1 shipped signed.

Home — full index

Start here

1. Install and run

2. Secure it

3. Operate it

4. Extend it

5. Contribute to it

Look it up — from any journey


About this wiki

Clone this wiki locally