Repository navigation
Governance
Source of truth: GOVERNANCE.md, kept in the repository and copied here. Re-copied on 26 September 2026 from the document as the tag v6.3.4 (51e2dbda0) has it, and on 5 October 2026 from the document as the tag v6.3.6 (e3c448aa6) has it (GOVERNANCE.md at v6.3.6): the two maintainers as one from Progressive Robot Ltd and one independent of it, release tags created by the
Progressiverobotaccount alone, and review through merge requests from the first change after 6.3.4. 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 (GOVERNANCE.md at v6.3.7), whose every paragraph that says who holds a role in the GitLab project, who approves a merge request, what the project access tokenlaptop-gitcan do and how the batches have landed had been brought to the same commit on 17 October 2026, before it was tagged - the status note, the first two paragraphs of The short version, the maintainers' accounts, the table of duties with the paragraph and the three notes after it, Ordinary changes, Review with the record of the landings by 14 October 2026, the opening of the reviewer's steps and the landing script's override, Security, the second maintainer's record under Becoming a maintainer, and the current status and the first three points of Continuity - and which changes nothing else. So it gives the members' roles as GitLab listed them on 14 October 2026 -Progressiverobotthe only person with a role in the project since 13 October 2026, when Zain Ul Abidin andchrisholloway5were removed, and the bot user of the revoked tokenlaptop-gitstill listed as an Owner - and says that every batch lands on the owner's override until somebody in the project can approve one. The map of which document governs what, and the note on code-signing material, are this wiki's own additions. Re-copied on 19 October 2026 from the document asmasterhas it from batch49, f14412d39 (GOVERNANCE.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 status note says that the accountProgressiverobotstays suspended and that the project is published on GitHub again, as GitLab's mirror, at https://github.com/RainbowWizard-coder/hMailServer, where GitLab's push mirror pushes the repository after every push, with every release, the labels and milestones, the wiki's copy and Discussions; GitLab is the one place the project is worked on, an issue is opened there alone, and a pull request on GitHub is read and, if it is accepted, landed through a GitLab merge request; GitHub's private vulnerability reporting is switched on and read by the maintainers; a release is built, signed and published on GitLab first and then copied to GitHub; the repository there belongs to Christopher Holloway's accountRainbowWizard-coder, its only administrator, and Zain Ul Abidin's accountZainulabidin90was removed from it on 18 October 2026; and accepting, reviewing and proposing a change take in a pull request on GitHub. The map's routes for a report and a question, and the note on code-signing material, say what the document says. Re-copied on 20 October 2026 from the document asmasterhas it from batch50, 0c0b6bae7 (GOVERNANCE.md at 0c0b6bae7), which changes it in one place: the note on keyless signing says that the token was GitHub's for the releases from 6.2.19 to 6.3.3, where it said the releases up to 6.3.3. Re-copied on 21 October 2026 from the document asmasterhas it from batch51, 5e49abf06 (GOVERNANCE.md at 5e49abf06), which changes it in one place: the status note says that GitHub Actions runs two workflows of the project's on GitHub,.github/workflows/scorecard.ymland.github/workflows/codeql.yml, which analyses the code there with CodeQL, and that neither builds, signs or publishes anything of a release, and that GitHub's rules there let the repository's administrator role, as which GitLab's push mirror pushes, alone writemaster, thebatch*branches and the release tags, and hold a pull request to two approvals, the code owner's among them (.github/CODEOWNERS), and to CodeQL's check, where it said that GitHub Actions ran Scorecard's one workflow and that GitHub's own CodeQL default setup analysed the code. Re-copied on 24 October 2026 from the document asmasterhas it from batch54, 9336fdd59, onmastersince 24 October 2026 (GOVERNANCE.md at 9336fdd59), which changes it in one place: the status note says that on GitHub the copies of 6.3.6 and 6.3.7, and every release published after them, are immutable, where it said a release published after that day's copies. The document's links to the repository's other documents point at them as 9336fdd59 has them, or at this wiki's copy where there is one.
This document describes how the hMailServer fork at hmailserver/hmailserver is run: who decides what, how decisions are made, and what each role is expected to do. It describes the project as it actually is today, not as an aspirational structure.
Status since 18 September 2026. The Progressiverobot account on GitHub,
the project's home there, was suspended on 18 September 2026 and stays
suspended: every link to github.com/Progressiverobot still answers 404, and the
issues, pull requests and discussions it held are still gone. The project's
home has been GitLab since 22 September 2026, and GitLab is canonical. Since
18 October 2026 the project is published on GitHub again, as a second home, at
https://github.com/RainbowWizard-coder/hMailServer, under the account
RainbowWizard-coder, as GitLab's mirror: the repository (master, the
batch* branches and every tag, which GitLab's push mirror has pushed there after
every push since that day), every release so far, 6.0.0-B1 to 6.3.7, with the
same files byte for byte, the project's labels and milestones, the wiki's copy and
Discussions. GitLab is the one place the project is worked on: an issue is opened
there alone, since the GitHub repository has no Issues, and a pull request on
GitHub is read and, if it is accepted, landed through GitLab, as a batch* branch
and a merge request, keeping its author and sign-off, so a change reaches master
only through GitLab, by the merge request described below. The pipelines run on
GitLab and nowhere else: GitHub Actions runs two workflows of the project's,
.github/workflows/scorecard.yml, which scores the repository with OpenSSF
Scorecard, and .github/workflows/codeql.yml, which analyses the code there with
CodeQL on each push to master, on each pull request and weekly, and whose
findings the maintainers read, nothing more; neither builds, signs or publishes
anything of a release. GitHub's rules there let the repository's administrator
role, as which GitLab's push mirror pushes, alone write master, the batch*
branches and the release tags, and hold a pull request to two approvals, the code
owner's among them (.github/CODEOWNERS), and to CodeQL's check
(Mirroring.md).
Where this document describes the
Progressiverobot account's GitHub repository - its ruleset and the approval
it required, repository admin, private vulnerability reporting, and release
signing through GitHub's token service - it describes how the project ran
there. On GitLab, up to and including 6.3.4, no approval was required (the
GitHub ruleset had stopped requiring one on 14 September 2026): master is
protected, and a change that had passed the regression gate landed on it by
fast-forward. From the first change after 6.3.4, every change is to land
through a merge request that a second person approves - Zain Ul Abidin, or the
owner for Zain's own - before the owner merges it, by fast-forward, once its
pipeline has passed and every thread on it is resolved; build/land-via-mr.py
(written on 26 September 2026) lands it that way and refuses a merge request
without that approval unless the owner overrides it (see Review). By 14 October
2026 nine batches had landed that way, the first on 29 September 2026: one,
batch45 (7 October 2026), with Zain Ul Abidin's approval, and eight on the
owner's override. Since 13 October 2026 Zain Ul Abidin holds no role in the
project, and no other person who could approve is a member of it, so every
landing is on that override until one is (Maintainers). The
owner takes direct pushes off master once the batch that brings the change
checks has landed through them (Security Policy, "Every change"); it
landed on 9 October 2026 (batch44), and on 14 October 2026 master still let
Maintainers push, so until he does, he can still push a gated tree to master
directly, as he did with 6.3.6's release fixes on 5 October 2026. Security
reports go by the routes in Security Policy; since 18 October 2026
GitHub's private vulnerability reporting is switched on for the repository
there too, and the maintainers read it. The release chain ran on
GitHub Actions up to 6.3.3; 6.3.4, published on 27 September 2026, was built and
signed by hand; and the chain's replacement, the release jobs of
.gitlab-ci.yml, made 6.3.5 on 29 September 2026 and 6.3.6 on 6 October 2026.
A release is built, signed and published on GitLab first and, since
18 October 2026, then copied to GitHub, where the copies of 6.3.6 and 6.3.7, and every release
published after them, are immutable; the update feed https://updates.progressiverobot.com,
the package repositories and the container registry are GitLab's.
The installer's fetched build inputs come from the project's package registry
on GitLab, and no build step downloads from GitHub: the project builds from
GitLab alone, so that no forge's suspension can stop a build again.
This project has two maintainers, Christopher Holloway and Zain Ul Abidin, and is stewarded by Progressive Robot Ltd. Decisions are made by the maintainers, in the open, on the issue tracker. Since 13 October 2026 Christopher Holloway is the only person with a role in the GitLab project, so every duty below that needs one is his alone for now (Maintainers).
On GitLab, since 26 September 2026, Christopher Holloway's account
Progressiverobot is the project's only Owner among its people and its only
person with the Maintainer role or above, and since 13 October 2026 its only
person with any role (its members, read through GitLab's API on 14 October
2026). Zain Ul Abidin (zainulabidin1990) held the Developer role from
26 September 2026, the owner's decision; on 13 October 2026 he was made a
Guest, to keep the group's GitLab subscription to its one seat, and then
removed from the project, and Christopher Holloway's older account
chrisholloway5, a Developer until then, was removed the same day. The project
access token laptop-git, which held the Owner role for work from the owner's
machine, is revoked; its bot user is still listed among the members with that
role, and nothing can act as it. master and the v* tags are protected for
Maintainers, so every change reaches master through the owner, and only he
can create a release tag, which the release job also holds to the one key in
.gitlab/allowed_signers.
The two maintainers are unassociated: Christopher Holloway is from Progressive Robot Ltd, and Zain Ul Abidin is independent of it (the owner's statement of 26 September 2026; an earlier version of this document said both worked for the company, which was wrong). Until September 2026 this document named Christopher Holloway as the project's only maintainer. That is stated plainly here for the same reason the project's size is stated in Security Policy: people relying on a mail server are entitled to know how much of it rests on how few people, and on which organisation. The Continuity section below says what is and is not currently true about that.
Currently: Christopher Holloway (Progressiverobot on GitLab, the Owner;
RainbowWizard-coder on GitHub since 18 October 2026, the account the project's
repository there belongs to and its only administrator; chrisholloway5, an
earlier GitHub account of his, and on GitLab an older account of his that was a
Developer in the project until 13 October 2026) and Zain Ul Abidin
(zainulabidin1990 on GitLab, a Developer in the project from 26 September to
13 October 2026 and not a member of it since; Zainulabidin90 on GitHub, removed
from the project's repository there on 18 October 2026).
The maintainers are accountable for the project. In practice this means:
-
Accepting changes. Reviewing merge requests on GitLab and, since
18 October 2026, pull requests on GitHub, landing them on
masterthrough a GitLab merge request (a pull request as abatch*branch, keeping its author and sign-off), and deciding what does and does not belong in the fork. - Releasing. Producing releases according to Release Process, including running the full regression suite against the exact binary being shipped, and signing every release asset.
- Security response. Receiving private vulnerability reports, triaging them, and meeting the timetable published in Security Policy.
- Direction. Keeping Roadmap.md current, and deciding what the project will deliberately not do.
- Infrastructure. Holding and protecting the credentials listed under Critical assets.
Who holds which today:
| Duty | Christopher Holloway | Zain Ul Abidin |
|---|---|---|
| Accepting changes | Yes | No, since 13 October 2026 ³ |
| Releasing | Yes | No ¹ |
| Security response | Yes | No ² |
| Direction | Yes | Yes |
| Infrastructure | Yes | No |
Christopher Holloway owns the GitLab project and holds the signing and release
path. On GitHub, until 18 September 2026, he held admin rights on the
repository, and Zain Ul Abidin held write access, which was enough to review and
merge pull requests and to run the release workflows. On GitLab, Zain Ul Abidin
held the Developer role from 26 September 2026, the owner's decision, and holds
no role in the project since 13 October 2026. On GitHub, since 18 October 2026,
the project's repository, https://github.com/RainbowWizard-coder/hMailServer,
belongs to Christopher Holloway's account RainbowWizard-coder, which administers
it, and nobody else holds write access there (its collaborators, read through
GitHub's API on 18 October 2026): Zain Ul Abidin's account Zainulabidin90, a
collaborator there at first, was removed from it that day, in line with his
holding no role in the project since 13 October 2026. Three of the duties above need
more than GitLab's Developer role gives, or a decision not yet made:
-
Releasing is the owner's alone. Release tags are created by
Christopher Holloway, as the
Progressiverobotaccount, alone (decided on 26 September 2026), and he is the only member GitLab lets create one: the protected tag rule forv*allows Maintainers, and he is the only person among the members with that role or above (the one other member listed with it, the bot user of the revoked tokenlaptop-git, can do nothing). That role is the real control. The protected-tag rule names the role, not his account, and a Maintainer'sv*tag runs the tagged commit's own.gitlab-ci.yml: any pipeline of a protectedv*tag is given a Sigstore certificate naming that tag, which every server built after 6.3.3 accepts. Thereleasejob's own checks -.gitlab/allowed_signersread asmasterhas it, exactly one key in it (his), the tag signed by that key, and the tagged commit onmaster- run as the tagged commit has them, so they stop a mistake and a tag pushed without his key, not a hostile commit; the Azure federated credential made for one tag at a time holds the installer's Authenticode signature alone (Release Process, "The release on GitLab"). Whoever is given the Maintainer role can therefore sign a release the servers accept. A release also needs a machine set up to run Release Process steps 4 to 11 — the regression suite, the fuzz runs and the installer build. -
Security response needs to see every report. Reports arrive as
confidential issues on GitLab, opened directly or by mail to the Service
Desk address (Security Policy), and GitLab shows a confidential
issue only to its author, its assignees and the project's members with the
Planner role or above; since 18 October 2026 a report may also arrive
through private vulnerability reporting, switched on for the project's
GitHub repository https://github.com/RainbowWizard-coder/hMailServer, which
the maintainers read. Zain Ul Abidin was a member of the GitLab project
from 24 September 2026 (
zainulabidin1990), a Developer from 26 September 2026, and so could see every report, until 13 October 2026; since then he is not a member, and sees none. Security response rests on Christopher Holloway, the one person who sees a report; whether Zain Ul Abidin takes the duty on, should he be a member again, is the maintainers' decision. (On GitHub, until 18 September 2026, reports arrived through private vulnerability reporting, which showed every advisory only to repository admins, security managers and organisation owners.) -
Accepting changes on GitLab needs the Maintainer role:
masteris protected, and only Maintainers may merge to it (or push to it, until the push rule becomes No one; ContinuousIntegration.md, "Landing on master"). As a Developer, from 26 September to 13 October 2026, Zain Ul Abidin could push branches of his own, open merge requests and review others', and from the first change after 6.3.4 he was the second person whose approval each merge request needs, the owner's batches included, before the owner merges it (see Review); his own changes, and a contributor's he had reviewed, reachedmasterthrough the owner, who reviews and lands them. Since 13 October 2026 he can do none of that in the project; like anyone, he can still comment on its public issues and merge requests, and open a merge request from a fork.
Anyone who opens a merge request (a pull request, on GitHub). Contributors are expected to follow Contributing: keep changes focused, keep the regression suite green, add or update regression tests for behaviour changes, use parameterised SQL exclusively, and accept that contributions are licensed under the AGPLv3.
Contributors do not need any prior status. There is no CLA to sign.
Anyone who files an issue or a security report. Reporters are expected to follow SUPPORT.md for defects, and Security Policy for anything security-relevant — in particular, not to open a public issue for a security problem.
Reporters are credited for security findings unless they ask not to be.
Ordinary changes. Either maintainer decides on a contributor's merge
request, and from the first change after 6.3.4 every change is to be approved by
a maintainer other than its author before it lands. Since 13 October 2026
nobody in the project can approve the owner's batches, in which every change
lands, so each lands on the owner's override (see Review). The reasoning is
recorded where the decision
happens — in the merge request, in the issue, or in the release notes. The
project's habit is to write down why rather than just what; the release
notes are the clearest example of this and are the intended place to look for
the reasoning behind a behavioural change. On GitLab, since 26 September 2026,
whoever decides, a change lands on master through the owner, the one member
with the Maintainer role (note 3 under Maintainers), and, from
the first batch it lands, through a merge request: the owner's own work as a
batch* branch that build/land-via-mr.py lands
(Contributing, "Merge requests"). Since 18 October 2026 a
pull request on GitHub is accepted too, and lands the same way: a maintainer
puts it on a batch* branch, keeping its author and sign-off, and a merge
request lands it, so whichever forge a change is proposed on, it lands on
master only through a GitLab merge request.
Review. From the first change after 6.3.4, every change lands on master
through a merge request, which Christopher Holloway, the owner, merges - by
fast-forward, with the merge request's pipeline green - once a second person has
reviewed and approved it (the owner's decision of 26 September 2026): Zain Ul
Abidin, for the owner's own changes, those an agent makes on his behalf,
contributors' and Renovate's, and the owner for a merge request of Zain Ul
Abidin's own. A reviewer asks for changes on the merge request rather than
pushing to the author's branch. While the reviewer is unavailable, a change
waits, or the owner lands it on his override (below).
That is the rule; this is the record. By 14 October 2026 nine batches had
landed through a merge request, the first on 29 September 2026. One, batch45
(!13, 7 October 2026), had Zain Ul Abidin's approval. Eight landed on the
owner's override, each with its reason on its merge request - from 6 October
2026 the owner's standing decision to leave a second person's approval unmet for
the moment - and Zain Ul Abidin reviewed one of them afterwards, batch43
(!12), on its merge request (the landing log, land-via-mr.log, and the merge
requests' notes). Since 13 October 2026 Zain Ul Abidin holds no role in the
project (Maintainers) and no other person who could approve is a
member of it, so until one is, every change lands on the owner's override and
waits for a reviewer to read it afterwards.
No approval rule is configured on the project, so nothing in GitLab makes an
approval a condition of the merge. What the project's merge settings do hold is
that a merge request merges only by fast-forward, only once its pipeline has
succeeded and only with every thread on it resolved. Whether an author may
approve their own merge request, and whether a new push takes an approval off,
are project settings; the landing script never counts an author's approval, and
counts only one given after the tip it lands reached the merge request, whatever
those settings say. So the approval is held by build/land-via-mr.py, and by
the owner, the one member who can merge; it is recorded on the merge request
rather than anywhere private, because that record is what shows that a second
person has read the change. master takes a Maintainer's direct push until the
owner closes it to direct pushes, which he does once the batch that brings the
change checks has landed through them
(ContinuousIntegration.md,
"Landing on master"; Security Policy, "Every change"), leaving the
merge request as the only way in; that batch, batch44, landed on 9 October
2026, and on 14 October 2026 master still let Maintainers push.
How a reviewer with the Developer role - Zain Ul Abidin, until 13 October 2026 - reviews one of the owner's batches:
- Open the merge request (
Land batchN: ..., opened bybuild/land-via-mr.py), and read the Changes tab, commit by commit where the batch is large (the Commits tab). - Say what must change as a comment on the line, which opens a thread. GitLab will not merge while a thread is unresolved; the author answers, changes the batch and pushes it again (a new pipeline), and the reviewer resolves the thread when the answer is right.
- When the change is right, press Approve. The approval is recorded on the merge request and in its activity. The landing script counts only an approval given after the tip it lands reached the merge request, so after a new push the reviewer approves again (Revoke approval, then Approve, where the old approval still shows).
build/land-via-mr.py reads the approvals just before it merges and records,
in a note on the merge request and in its log, whether somebody other than the
author approved the tip it lands: not the merge request's author, not an
author of one of its commits, not another account of the same person
(Progressiverobot and chrisholloway5 are both Christopher Holloway's), and
not an approval given before that tip reached the merge request (its diff
versions say when). Without such an approval it refuses to merge (exit 7), and
the landing note says so. The owner alone may override that for one landing,
when waiting would hold up something urgent - a security fix inside its
disclosure window, or a broken build on master - or, since 6 October 2026,
under his standing decision to leave the approval unmet for the moment, with
python3 build/land-via-mr.py batchN --land-without-approval "<reason>": the
script refuses the override unless it runs as one of the owner's accounts, and
records the reason in the landing note and its log; a change landed that way is
to be reviewed afterwards, on its merge request. A batch that changes the gates' own
files - the change checks' scripts, .gitlab-ci.yml and the CI files their
jobs are in or take a part from, the landing script,
build/check-release-chain.py, the sign-off check and the secret scan the
landing runs and that scan's rules script, and the source scans' scripts -
lands only with
--gates-read "<reason>", the
word of the person who read that change whole, which the landing note records:
a change to what judges every change is read by a person, not by the gates it
changes. A contributor's merge request on GitLab, or pull request on GitHub, is
approved by a maintainer on that merge request or pull request before its
commits are put on a batch; a fork's pipeline runs in the fork, and no pipeline
of the project's runs on GitHub, so neither result is the gate, and the batch's
pipeline is (Security Policy, "Every change").
On GitHub, until 14 September 2026, a pull request authored by one maintainer, or opened by an agent on one maintainer's behalf, was approved by the other before it was merged, and the master ruleset enforced this: a merge needed an approving review from someone other than the last person to push. A pull request Copilot opened under its own identity, rather than for one maintainer, needed both maintainers' approval: the ruleset added one approval for those. When waiting would have held up something urgent — a security fix inside its disclosure window, or a broken build on master — only an administrator on the ruleset's bypass list could merge first, and a change merged that way was reviewed afterwards, its pull request saying that it was merged before review, and why.
Disagreements. Raise them on the issue in question. A maintainer will respond with a reason, not just a verdict. A closed issue is not a closed conversation — reopening it with new information (especially a reproduction) is welcome, and has changed outcomes before. If the maintainers disagree, both positions are written on the issue and Christopher Holloway decides, recording the reason there. When that decision is to merge a merge request the other maintainer has not approved, the other maintainer approves it and records the disagreement in the review.
Scope. Whether something belongs in the fork is decided against one question: does it serve people running this as a mail server in production? Compatibility with existing hMailServer deployments is a standing constraint, not a preference — an upgrade must preserve configuration and mail.
Security. Security decisions are made under the disclosure timetable in Security Policy, not by consensus. They are the maintainers' to make, and either maintainer may decide alone when waiting for the other would miss that timetable. Only Christopher Holloway sees a report and can publish an advisory (the second note under Maintainers), so in practice those decisions are Christopher Holloway's; and a fix authored by Zain Ul Abidin always needs Christopher Holloway's approval to merge (see Review).
There is no committee and no fixed number of contributions. The path is demonstrated, sustained judgement: a track record of changes that are correct, tested, and considerate of existing deployments, plus a willingness to take on the release and security duties above rather than only the coding.
If you want to help at that level, say so on an issue. The project would benefit from it — see Continuity.
The second maintainer did not come by that route. Zain Ul Abidin, who is
independent of Progressive Robot Ltd, was appointed by the owner in September
2026, before building a track record in this repository; that record was to be
built through the review rule under How decisions are made,
and when he stopped holding a role in the GitLab project, on 13 October 2026,
it held one approval of his (batch45, !13) and one review after a landing
(batch43, !12).
These are the things whose loss would stop the project, and they are listed so that a successor knows what to look for:
| Asset | What it is for |
|---|---|
| GitLab project owner | Project settings, protected branches and tags, CI/CD variables, confidential issues, and granting access (on GitHub, until 18 September 2026: repository admin, with its rulesets, secrets, private vulnerability reports and security advisories) |
| Release signing path | Sigstore cosign keyless signing of release assets, and the SSH keys listed in .gitlab/allowed_signers that sign release tags (one today, Christopher Holloway's) |
| Code-signing material | Signing the Windows installer |
| Build environment recipe | Visual Studio 2026 / v145 plus the external libraries under hMailServerLibs
|
| Test environment recipe | The database, ClamAV, SpamAssassin and INI configuration the full regression suite needs |
Everything needed to build, test, release and verify the product is
committed to this repository and documented — in
README.md, Architecture,
Release Process, the scripts under build/, and the pipeline in
.gitlab-ci.yml. Deliberately, nothing about producing a release depends
on knowledge that exists only in one maintainer's head.
Note that release-asset signing is keyless (Sigstore, via the CI's OIDC
token: GitHub's for the releases from 6.2.19 to 6.3.3, GitLab's from 6.3.5),
so there is no private key behind it to inherit or to lose, which removes the
single most common continuity failure for a small project. Release tags are
signed with the owner's own SSH key, the one key
.gitlab/allowed_signers may hold, Christopher
Holloway's; a lost key is replaced by putting a new one in its place on
master, not inherited.
Current status: two maintainers, one from Progressive Robot Ltd and one
independent of it, of whom only the first holds a role in the GitLab project
since 13 October 2026; access continuity is arranged; the record of knowing the
codebase is still one person's. Christopher Holloway keeps the critical credentials in a managed
arrangement that a trusted person can reach if Christopher Holloway is
confirmed unavailable, together with the legal authority to use them, so the
project could create and close issues, accept changes and publish a release
within days rather than being locked out. On GitHub, a second maintainer with
write access meant a contributor's pull request could be reviewed and merged
without that arrangement, though Zain Ul Abidin's own pull requests could not
be: the master ruleset required an approval from someone other than the last
person to push until 14 September 2026, and GitHub does not let authors approve
their own pull requests. On GitLab, since 26 September 2026, only the owner can
push or merge to master, so while he is unavailable every change, Zain Ul
Abidin's included, waits on the arrangement too; and from the first change
after 6.3.4 every change is also to wait for the other maintainer's approval,
which since 13 October 2026 nobody in the project can give, so that each lands
on the owner's override (see Review).
What remains true, stated as plainly as the single-maintainer position was:
- The record is one person's. Every commit on master made by a person before 11 September 2026 was authored by Christopher Holloway, and none of Christopher Holloway's pull requests had been approved by anyone else, so the repository does not yet show a second person who knows the codebase. That changes only as both maintainers review and write changes here; the review rule under How decisions are made, which has a second person approve every merge request from the first change after 6.3.4, is what would build that record, and it has built little of it so far: one approval and one review after a landing, Zain Ul Abidin's, by 13 October 2026, when he stopped holding a role in the project.
- Administration rests on one person. Only Christopher Holloway, among people, holds the Owner role on GitLab, and with it the only Maintainer rights, and the credentials under Critical assets; while Christopher Holloway is unavailable, settings, rulesets, access and security advisories wait on the arrangement above.
- Two of the duties need more than the Developer role. Accepting changes and releasing need the Maintainer role, which is the owner's alone, and releasing needs a release machine besides. Security response needs access to private reports, which a Developer has and somebody who is not a member of the project, as Zain Ul Abidin is not since 13 October 2026, does not; taking it on is the maintainers' decision. See the notes under Maintainers.
- Mostly one organisation, for now. The maintainers are unassociated - Christopher Holloway is from Progressive Robot Ltd, Zain Ul Abidin is independent of it - but the administration, the release path and, so far, nearly every change are the Progressive Robot maintainer's. The dependence on one organisation lessens only as the independent maintainer's reviews and changes accumulate here.
The mitigations that were in place for a single maintainer still hold:
- Every build, test and release step is scripted and committed, so the work is reproducible by someone else without tacit knowledge.
- Release-asset signing requires no inherited private key, and a tag-signing key is replaced rather than inherited.
- The repository is public, on GitLab and, since 18 October 2026, on GitHub too, and the licence (AGPLv3) permits anyone to continue the work — a fork is always available as a last resort, which is precisely how this project itself came to exist.
The project is open to further maintainers; see Becoming a maintainer.
This project keeps its rules in the repository, next to the code they govern, and copies each into this wiki. If you are not sure which one applies, this is the map.
flowchart TB
Q["What are you trying to do?"]
Q --> C1["Send a change"]
Q --> C2["Report a defect"]
Q --> C3["Report a vulnerability"]
Q --> C4["Ask a question"]
Q --> C5["Cut a release"]
Q --> C6["Understand a decision"]
Q --> C7["Change how the project is run"]
C1 --> D1["CONTRIBUTING.md<br/>focused changes, tests,<br/>parameterised SQL, DCO sign-off"]
C2 --> D2["SUPPORT.md, then an issue<br/>with the Bug template"]
C3 --> D3["SECURITY.md<br/>a confidential issue, the<br/>Service Desk address or GitHub's<br/>private vulnerability reporting -<br/>never a public issue, discussion<br/>or pull request"]
C4 --> D4["An issue on GitLab with the<br/>Question template, the Q&A of<br/>GitHub's Discussions, or the<br/>hMailServer forum for general<br/>hMailServer questions"]
C5 --> D5["RELEASE.md<br/>fourteen ordered steps<br/>and their gates"]
C6 --> D6["The merge request, the issue,<br/>or the release notes -<br/>whichever is where the<br/>decision happened"]
C7 --> D7["GOVERNANCE.md<br/>by merge request, like<br/>everything else"]
D1 --> M["The maintainers decide,<br/>with a reason recorded<br/>where the decision happens"]
D3 --> M
D5 --> M
D7 --> M
The rule behind that last box is the one worth internalising: the reasoning is written down where the decision happens. The release notes are the clearest example and are the intended place to look for why a behaviour changed.
A note on the Code-signing material row in Critical assets:
since 11 September 2026 the installer is Authenticode-signed with Azure Artifact
Signing (the service formerly called Trusted Signing), from 6.3.1. There is still
no certificate file to inherit or lose: Microsoft holds the key and issues short-lived
certificates against an organisation identity validation of Progressive Robot Ltd,
and the release workflow signed through an Azure app registration whose secret was
held in GitHub Actions' secrets, so that workflow could not sign once GitHub had
suspended the project's account (see the status note at the top); 6.3.4 was Authenticode-signed by hand,
outside it. From 6.3.5 the release-authenticode job of .gitlab-ci.yml signs it
with no secret at all: the job's GitLab ID token is accepted by Microsoft Entra ID
through a federated credential, issued for one release tag at a time
(Release Process, Authenticode). What a successor would need is the Azure subscription, the signing account and the identity
validation, which lapses and must be renewed - RELEASE.md records all three.
Propose changes the same way as any other change: open a merge request on GitLab, or a pull request on GitHub. The maintainers decide, and, as everywhere else in this project, give a reason.
hMailServer 6.3.7, the latest release (17 October 2026, schema 6108) · AGPL-3.0-or-later · Repository · Mirror on GitHub · Report a documentation error (a GitLab issue naming the page)
Home — full index
Start here
1. Install and run
- Before You Install
- Installing hMailServer
- Installing on Linux
- Running in a Container
- Profiles and Environment
- The Control Panel
- The Control Deck
- Your First Domain and Mailbox
- Connecting a Mail Client
- The Webmail
- DNS for Your Domain
- Migration
2. Secure it
- Encryption and Certificates
- Database TLS
- Encryption for People
- Stopping Spam
- Stopping Viruses
- Security Hardening
- Secure Defaults
- The Service Account
- Secrets at Rest
- Sign-in and Identity
- Security Policy
3. Operate it
- Monitoring and Health
- The SNMP Agent
- Backup and Restore
- Message Storage
- Compliance and eDiscovery
- Troubleshooting
- Diagnosing Stalled Mail
- Relocating an Installation
- Upgrading hMailServer
- Upgrading Guide
- The Update Feed
- Migrating the Database Backend
- High Availability Runbook
- Warm Standby
- Runbooks Digest
4. Extend it
- Rules and Sieve
- Aliases Lists and Public Folders
- Rooms and Equipment
- Mailing Lists
- Routes and Relays
- Mail In to a Webhook
- Outbound Shaping
- The COM API and Scripting
- Event Scripts
- 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
- Settings Reference
- Settings Overview
- Capabilities and Configuration
- Control Panel Reference
- Control Panel Pages
- Ports Reference
- Changes-Since-6210
- Version-History-to-6210
- Glossary
About this wiki
- hMailServer 6.3.7 is the latest release (17 October 2026, schema 6108)
- Pages say since 6.3.4 where a feature is new in it
- AGPL-3.0-or-later
- Repository, the one place the project is worked on
- Its mirror on GitHub, since 18 October 2026, with no Issues
- Questions: a GitLab issue with the Question template, GitHub Discussions Q&A, or the forum
- Report a documentation error: a GitLab issue naming the page