sirius-press/docs/upstream-merges.md
Silent Mode 5465b65756 feat(sirius-press): a WordPress where the account is a key, not a mailbox
WordPress makes two assumptions this project cannot accept: that identity
comes from an email address, and that a site lives at one server. Both are
things somebody else can take away — a mailbox is rented from a provider who
can close it or be compelled to open it, and a server is one seizure from
being gone.

Sirius Press replaces the first and hedges the second.

Signing in means signing a challenge with the key that controls a CashAddress.
The address is recovered from the signature, so nothing is typed but the
signature itself, and the result is an ordinary WordPress session cookie —
roles, capabilities, nonces and the REST API never learn the login was
different. Three ways to produce one: a wallet the browser already exposes, a
phrase used once in the page and wiped, or a signature pasted in from any
BIP-137 wallet, which needs no JavaScript and lets the key stay on a machine
that never touches the web.

There is no password reset, and the recovery page says so plainly rather than
offering a form that cannot work. A reset mechanism is by construction a way
to take an account from its owner, and it is always easier to attack than the
cryptography it bypasses.

Publishing a post also exports it as static HTML to the name's storage on Sia,
signed by the key that owns the name, so the site keeps answering when the
server does not.

Email as a feature is untouched. wp_mail() still works, SMTP still sends, and
contact forms still deliver to addresses real people typed. Only mail to the
site's own unroutable placeholder addresses is diverted to an in-app inbox.
The objection was to email as identity, not to email.

Core is pinned and patched rather than vendored. WordPress 7.1.1 is 149 MB and
5,008 files; the fork's entire core diff is 75 lines in wp-admin/install.php.
Carrying the former to express the latter would bury the patch where nobody
reviews it and make every clone of the monorepo pay for it. Upstream releases
still merge through tools/update-wordpress.sh, which reapplies the series and
says exactly which hunk needs a human.

The cryptography is implemented twice — PHP on the server, JavaScript in the
page — because the server must verify and the browser must sign. Both are
pinned against libauth, the library the Sirius portal wallet and the BNS
gateway already use, so a disagreement of one byte fails the test suite rather
than presenting as a rejected login at three in the morning.

132 checks, no framework, about a second.
2026-09-21 01:39:38 +02:00

4.2 KiB

Keeping up with WordPress

WordPress ships security releases, and a fork that cannot take them quickly is a liability rather than a project. This page is how Sirius Press takes them.


The arrangement

WordPress is not in this repository. Instead:

  • tools/wordpress.lock pins an exact version, its download URL and its SHA-256.
  • patches/ holds the fork's core diff as a patch series.
  • tools/build.sh and the Docker image each download the pinned tarball, verify the hash, and apply the series.

The entire core diff is currently one file, 75 lines: the setup wizard, at wp-admin/install.php. Everything else the fork does is plugins and hooks.

Why not a vendored subtree

The original plan was to vendor core as a git subtree, which is the standard way to run a fork with a substantial diff. Two numbers argued against it.

WordPress 7.1.1 is 149 MB and 5,008 files. The fork's core diff is 75 lines. Carrying the first to express the second means every clone, every git status, every git subtree split in the parent monorepo pays for a patch you can read in a minute — and it buries that patch in a haystack where nobody will ever review it again.

A patch series makes the opposite trade. The core change is a file you can read in one sitting, review in a pull request, and re-read whenever it stops applying. The cost is that upstream merges are patch rather than a three-way git merge — which, for 75 lines in one file, is not much of a cost.

This holds as long as the diff stays small. If the fork ever needs to change core substantially, vendor it properly: see "Switching to a subtree" below.


Taking a new release

tools/update-wordpress.sh 7.1.2

It fetches the release, verifies its SHA-1 against what wordpress.org publishes, records a SHA-256, applies the patch series to the new tree, and reports what happened.

Three possible outcomes:

Clean. The series applied. tools/wordpress.lock is updated, the tests run, and you commit the lock change. Usually thirty seconds of work.

Applied with fuzz. Upstream moved code near a hunk but not the hunk itself. The script says which hunk and by how many lines. Look at the result, then refresh the series so the next release starts from a clean base:

tools/update-wordpress.sh 7.1.2 --refresh

Failed. Upstream rewrote the code the patch touches. This is the case that needs a person: open the new wp-admin/install.php, redo the change by hand, and regenerate the patch. The script leaves the unpacked tree in dist/.upstream/ so there is something to work in.

In every case the fork is not broken while you work — the lock file still points at the last known-good version, and builds keep producing that until you change it.


Reviewing a release before taking it

Security releases are usually small, and it is worth knowing what changed near the code the fork patches:

tools/update-wordpress.sh 7.1.2 --diff wp-admin/install.php

prints upstream's own diff for that file between the pinned version and the new one. If it is empty — which it usually is — the patch will apply and there is nothing to think about.


After any bump

tests/run.sh

The suite does not test core, but it does test every assumption the fork makes about it. Then build and try an actual install:

tools/build.sh
cd docker && docker compose build && docker compose up -d

and walk through wp-admin/install.php once. The setup wizard is the only patched file, so it is the only thing an upstream change can break in a way the tests would miss.


Switching to a subtree

If the diff ever grows past what a patch series is comfortable with, the mechanics are:

git remote add wordpress https://github.com/WordPress/WordPress.git
git fetch --depth=1 wordpress 7.1.1
git subtree add --prefix=wordpress FETCH_HEAD --squash

and then, per release:

git fetch --depth=1 wordpress 7.1.2
git subtree merge --prefix=wordpress FETCH_HEAD --squash

with patches/ becoming the record of what was changed rather than the mechanism that changes it. The build script would then copy wordpress/ instead of downloading and patching.

Worth doing when the core diff reaches, say, a dozen files. Not before.