• v1.12.18 351fdd00c4

    Morphit v1.12.18
    All checks were successful
    morphit-ci / Supply-chain audit gate (fail on new high/critical) (push) Successful in 21s
    morphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 46s
    morphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 38s
    morphit-ci / Integration tests (real Postgres 16) (push) Successful in 41s
    morphit-ci / ansible-lint (playbook quality gate) (push) Successful in 15s
    morphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 26m2s
    morphit-release / Build + publish release tarball (push) Successful in 35m1s
    Stable

    agorise released this 2026-08-26 20:03:17 +00:00 | 54 commits to main since this release

    Signed by agorise
    GPG key ID: 53524E1F1017EB9C

    Morphit v1.12.18

    Theme: name your hidden-RPC nodes, and stop the stats card crying wolf.

    Added

    Optional operator names for hidden-RPC nodes. A node pinned to the on-chain directory (morphit_rpc_v1) can now carry an optional handle — a hostname like oldpc, or a Blurt @handle — so a misbehaving node can be identified and its operator reached. The name is opt-in (omit it and nothing lands on the chain), cosmetic, and never used to route or trust a node. Names appear on the public /v1/rpc-endpoints JSON, and — like adding or removing a node — a name change propagates to every instance within about a minute, no release required.

    /v1/rpc-endpoints is now sorted by latency. The endpoint list (clearnet and hidden together) is returned fastest-first, with unmeasured nodes last — matching the stats page's ordering.

    Fixed

    The stats page no longer flags a healthy node as "unreachable" on a single blip. The card shows the smoothed pool health, then fires one fresh probe and repaints with it — so a node on flaky WiFi or a jittery Tor/I2P circuit could miss that one ping and flash red while being up the vast majority of the time. A lone transient miss on a node the smoothed snapshot still considers healthy now stays up with its last-known latency. A genuine outage still shows red — the smoothed health drops and the failures climb.

    Notes

    • Database migration in this release: an additive, idempotent column on rpc_directory for the optional node names (safe on a running database; nothing to do by hand).
    • Everything from v1.12.17 and earlier (the live on-chain hidden-RPC directory on the stats page, the attack-resilience edge hardening, and the incident runbook) is included.
    Downloads
  • v1.12.17 7b75916864

    Morphit v1.12.17
    All checks were successful
    morphit-ci / Supply-chain audit gate (fail on new high/critical) (push) Successful in 20s
    morphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 48s
    morphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 45s
    morphit-ci / Integration tests (real Postgres 16) (push) Successful in 39s
    morphit-ci / ansible-lint (playbook quality gate) (push) Successful in 15s
    morphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 25m33s
    morphit-release / Build + publish release tarball (push) Successful in 33m56s
    Stable

    agorise released this 2026-08-24 22:33:59 +00:00 | 55 commits to main since this release

    Signed by agorise
    GPG key ID: 53524E1F1017EB9C

    Morphit v1.12.17

    Theme: the hidden-RPC directory is now live on the stats page — pin a node, everyone sees it, no release required.

    Changed

    The stats page's RPC list now reflects the on-chain directory, network-wide, automatically. Previously the hidden-service (Tor/I2P) nodes shown on the stats card came from a value baked into each indexer at startup, so a node pinned to the chain (morphit_rpc_v1) never appeared without a rebuild. Now every indexer serves its RPC list as its configured seed plus the live on-chain rpc_directory, re-derived per request (cached ~60s). The effect:

    • Pin a hidden node on-chain → it appears on every instance's stats page within the indexer's normal indexing lag, on the user's next visit. No per-operator action, no Morphit release.
    • Remove one → it drops off (the directory is latest-wins).
    • Clearnet nodes are unchanged (still hardcoded), still mixed in and sorted by latency.
    • Privacy is preserved: a tor-only instance still never probes clearnet nodes; hidden directory nodes are reached over Tor/I2P as before.

    This is the one-time wiring change. After this release, adding, updating, or removing hidden-RPC nodes is release-free forever.

    Fixed / Hardened

    • CI can no longer be tripped by a stray vendor/ folder. The offline-appliance build output (vendor/) is now git-ignored (root-anchored, so the real ops/ansible/roles/vendor is untouched), and the source-scan smoke skips broken symlinks instead of crashing on them.

    Notes

    • No database migration in this release.
    • Everything from v1.12.16 and earlier (the attack-resilience edge hardening, the incident runbook, the security-audit set, the CI supply-chain gate) is included.
    Downloads
  • v1.12.16 c686e4fc7a

    Morphit v1.12.16
    All checks were successful
    morphit-ci / Supply-chain audit gate (fail on new high/critical) (push) Successful in 21s
    morphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 46s
    morphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 38s
    morphit-ci / Integration tests (real Postgres 16) (push) Successful in 39s
    morphit-ci / ansible-lint (playbook quality gate) (push) Successful in 15s
    morphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 25m6s
    morphit-release / Build + publish release tarball (push) Successful in 33m15s
    Stable

    agorise released this 2026-08-24 00:23:19 +00:00 | 57 commits to main since this release

    Signed by agorise
    GPG key ID: 53524E1F1017EB9C

    Morphit v1.12.16

    Theme: attack-resilience hardening — tighter edge limits, faster slow-drip shedding, and a one-page incident runbook.

    Hardened

    Per-IP concurrent-connection cap at the edge. Every public vhost (relay, indexer, web) now caps simultaneous connections per client IP (limit_conn), so a single host can't exhaust connection slots even while staying under the request-rate limits. The cap is set generously so shared IPs (carrier-grade NAT, Tor exits) aren't affected.

    Slow-drip (slowloris) timeouts on all vhosts. The indexer and web vhosts now apply the same tight client_body/client_header/send timeouts the relay already used, instead of falling back to nginx's longer defaults — slow-header/slow-body connections are dropped quickly.

    Added

    Operator incident runbook (docs/INCIDENT-RUNBOOK.md). A single-page, top-to-bottom playbook for responding to an active attack, with exact reversible commands: halt signups instantly via the runtime kill switch (no restart), watch the balance/ceiling and price-disagreement alerts, ban abusive IPs/ASNs at the edge, and disclose privately. Consolidates controls that already existed into one sheet you can act on in seconds.

    Changed

    FAQ wording. The "What is Morphit?" answer now describes Morphit as a decentralised/distributed bulletin board service (DBBS) rather than a plain bulletin board service (BBS), across all supported locales.

    Notes

    • No database migration in this release.
    • The edge-config changes ship in ops/nginx/*.conf; apply them on the host with sudo nginx -t && sudo systemctl reload nginx.
    • Everything from v1.12.15 and earlier (the federation brand↔relay display fix, the relay/indexer security hardening, the block-explorer op labels, and the CI supply-chain gate) is included.
    Downloads
  • v1.12.15 1e183bf80a

    Morphit v1.12.15
    All checks were successful
    morphit-ci / Supply-chain audit gate (fail on new high/critical) (push) Successful in 24s
    morphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 49s
    morphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 40s
    morphit-ci / Integration tests (real Postgres 16) (push) Successful in 41s
    morphit-ci / ansible-lint (playbook quality gate) (push) Successful in 17s
    morphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 25m0s
    morphit-release / Build + publish release tarball (push) Successful in 32m3s
    Stable

    agorise released this 2026-08-21 20:48:12 +00:00 | 59 commits to main since this release

    Signed by agorise
    GPG key ID: 53524E1F1017EB9C

    Morphit v1.12.15

    Theme: instances that share a brand — a public identity account and a separate relay account — now display correctly across the federation.

    Fixed

    A federated instance is no longer flagged as a spoof for using a separate relay account. The federation directory verifies that the account a peer advertises as its relay matches the account that registered its origin on-chain — a guard against one instance claiming another's identity. That guard required the two to be the same account, which flagged a legitimate and secure setup: registering under a public brand account (which holds the reserved brand tag) while doing operational signing from a separate relay account. The probe now accepts this pairing when both accounts are reserved brand names — reserved names can only ever be registered by their rightful owner, so two reserved accounts are provably controlled by the same operator. This does not weaken the guard: reserved names cannot be registered by anyone else in the first place, and an instance advertising a relay account that is not reserved and does not match its operator is still flagged. No on-chain re-registration is required.

    A signup invite can no longer be used twice by two simultaneous requests. A single-use invite is verified up front but only marked spent once the account actually lands on-chain, so a failed broadcast doesn't burn a legitimate user's invite. Under a precisely-timed pair of concurrent requests, both could pass verification before either marked the invite spent — creating two accounts from one invite, and since each account creation spends real BLURT from the relay wallet, draining more than intended. The invite is now claimed atomically at the moment of broadcast: a second concurrent request presenting the same invite is rejected, and the claim is released on a failed broadcast so retries still work.

    Hardened

    The relay's decrypted key can no longer be paged to disk. The relay systemd unit now disables swap for the process (core dumps were already disabled), so the active-key material held in memory during signing cannot be written to disk by the kernel.

    A shared-relay-account misconfiguration is now detected. If two instances were accidentally pointed at the same relay account, each would credit the same signup's welcome bonus from its own independent database. The federation probe now detects when another instance advertises this instance's relay account and alerts the operator, converting a documented footgun into an enforced check.

    A supply-chain gate now guards dependencies. CI fails on any new high- or critical-severity dependency advisory that isn't in a triaged baseline, so a newly-vulnerable dependency can't enter the tree unnoticed. This release also completed a full security review of the relay, indexer, web/edge, and dependency surfaces.

    Changed

    The block explorer labels three more op types specifically instead of the generic "Other app": blockchain snapshots ("Blockchain snapshot"), the hidden RPC node directory ("Hidden RPC nodes"), and notifications ("Notification"). Translated across all supported locales.

    Notes

    • No database migration in this release.
    • Everything from v1.12.14 and earlier (the relay-health fix, auto-detect hardening, instances-page copy) is included.
    Downloads
  • v1.12.14 4a4dc53d7f

    Morphit v1.12.14
    All checks were successful
    morphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 49s
    morphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 39s
    morphit-ci / Integration tests (real Postgres 16) (push) Successful in 41s
    morphit-ci / ansible-lint (playbook quality gate) (push) Successful in 16s
    morphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 25m2s
    morphit-release / Build + publish release tarball (push) Successful in 35m19s
    Stable

    agorise released this 2026-08-20 21:53:37 +00:00 | 60 commits to main since this release

    Signed by agorise
    GPG key ID: 53524E1F1017EB9C

    Morphit v1.12.14

    Theme: /v1/health reports the relay's true state — the fix, verified live. Plus the auto-detect hardening around it and a small instances-page copy change.

    Fixed

    A healthy relay no longer reads as up:false on /v1/health. On a node whose indexer runs under a systemd sandbox, os.networkInterfaces() — called while building the relay-probe candidate list — threw EAFNOSUPPORT ("Unknown system error 97") because the unit's RestrictAddressFamilies did not include AF_NETLINK, the address family libuv needs to enumerate interfaces. That exception rejected the entire relay probe before any network request was made, so the health snapshot kept its default false and never recovered — a running, reachable relay reported as down. Two changes fix it: the probe's interface enumeration is now wrapped so it can never throw out of the probe (it falls back to the configured URL and loopback), and the indexer service unit now grants AF_NETLINK so interface enumeration works and the relay auto-detection functions fully. Verified on a live node: the endpoint flips from up:false to up:true.

    Changed

    • The relay-reachability probe auto-discovers the relay across every local address it could bind — loopback, each host interface (including the docker bridge a container-fronted relay uses), and the gateway — with no configuration required; a configured MORPHIT_INDEXER_RELAY_HEALTH_URL is still honoured. The local probe uses node:http directly.
    • Instances page: the bookmarking tip now reads "bookmark a few of these instances — and their Tor, I2P, Lokinet or ENS addresses" and notes that because the orderbook lives on the public blockchain, the same orders and trades are reachable in many other places if any one site is inaccessible.

    Removed

    • Two internal coordination documents (HIDDEN-RPC-Q2-RESPONSE.md, HIDDEN-RPC-SNAPSHOT-INSTRUCTIONS.md) removed from the repository.

    Notes

    • No database migration in this release.
    • Operators upgrading from a build that showed relay:up:false while morphit-ops health showed the relay up: this release is that fix. The unit change takes effect once the updated morphit-indexer.service is installed by the upgrade.
    • Everything from v1.12.13 and earlier is included.
    Downloads
  • v1.12.13 f21bf8276c

    Morphit v1.12.13
    All checks were successful
    morphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 50s
    morphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 41s
    morphit-ci / Integration tests (real Postgres 16) (push) Successful in 41s
    morphit-ci / ansible-lint (playbook quality gate) (push) Successful in 16s
    morphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 31m44s
    morphit-release / Build + publish release tarball (push) Successful in 37m53s
    Stable

    agorise released this 2026-08-20 18:23:01 +00:00 | 61 commits to main since this release

    Signed by agorise
    GPG key ID: 53524E1F1017EB9C

    Morphit v1.12.13

    Theme: the real fix for /v1/health reporting a healthy relay as down. The probe was being routed through the wrong network layer.

    Fixed

    /v1/health now reports the relay's true up/down state on a node that uses hidden (Tor/I2P) RPC endpoints. A node configured with Tor or I2P Blurt RPC installs a global request-routing dispatcher so chain reads go over those networks. The relay-health probe used the ordinary global fetch, so its request to the local relay was sent through that same Tor/I2P routing layer — which breaks a local connection — and a perfectly healthy relay read as up:false. (This is why the earlier candidate-selection fixes didn't resolve it: the probe was finding the right address, but the request itself was being misrouted.) The probe now connects to the relay directly, bypassing the global router entirely — a local health check has no business going through the Tor/I2P layer. Verified with a dispatcher-bypass test: a request through the router fails, the same request direct succeeds.

    Notes

    • No database migration in this release.
    • Diagnosis note for operators: this only affected nodes that have hidden RPC endpoints configured (which install the global router). A clearnet-only node was unaffected. If your node showed relay:up:false while morphit-ops health showed the relay up, this is the fix.
    • Everything from v1.12.12 and earlier is included.
    Downloads
  • v1.12.12 c1e87c611e

    Morphit v1.12.12
    All checks were successful
    morphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 47s
    morphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 39s
    morphit-ci / Integration tests (real Postgres 16) (push) Successful in 40s
    morphit-ci / ansible-lint (playbook quality gate) (push) Successful in 17s
    morphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 29m44s
    morphit-release / Build + publish release tarball (push) Successful in 35m50s
    Stable

    agorise released this 2026-08-20 05:21:25 +00:00 | 62 commits to main since this release

    Signed by agorise
    GPG key ID: 53524E1F1017EB9C

    Morphit v1.12.12

    Theme: the relay's health shows up correctly with zero configuration. One fix, applying a principle: a node should auto-detect its own topology, not make the operator hand-configure it.

    Fixed

    /v1/health now reports the relay's real up/down state without any configuration. The relay-reachability probe only worked when the operator set MORPHIT_INDEXER_RELAY_HEALTH_URL, and even the fallback only tried loopback. But the relay doesn't always listen on loopback: behind a containerized web front (BunkerWeb/nginx), it binds the docker bridge address (e.g. 172.18.0.1) so the container can reach it. With the probe URL unset — the default — a perfectly healthy relay read as up:false, disagreeing with morphit-ops health and a direct request. The probe now always auto-discovers the relay across every address it could bind — loopback, each host interface (which includes the docker bridge), and the default gateway — at the relay's canonical /v1/health path. No configuration required; a configured URL is still honoured verbatim when present, and a public URL can no longer misdirect the local probe onto :443 or a reverse-proxy path.

    Notes

    • No database migration in this release.
    • This continues the direction from v1.12.11 (the warrant canary auto-detecting tor-only and its own hidden RPC): a node should discover its own topology rather than depend on the operator getting a config value exactly right. Required configuration for things a node can determine itself is a source of silent, hard-to-diagnose breakage.
    • Everything from v1.12.11 (the tor-only canary routing, the operator-tag live display, the Matrix link, and the federation mismatch reclassification) is included.
    Downloads
  • v1.12.11 16efb945e4

    Morphit v1.12.11
    All checks were successful
    morphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 47s
    morphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 39s
    morphit-ci / Integration tests (real Postgres 16) (push) Successful in 40s
    morphit-ci / ansible-lint (playbook quality gate) (push) Successful in 15s
    morphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 30m3s
    morphit-release / Build + publish release tarball (push) Successful in 37m58s
    Stable

    agorise released this 2026-08-20 02:29:07 +00:00 | 63 commits to main since this release

    Signed by agorise
    GPG key ID: 53524E1F1017EB9C

    Morphit v1.12.11

    Theme: finishing tor-only node bring-up. This release fixes the problems a real tor-only deployment hit end to end — the warrant canary silently fetching its freshness proofs over clearnet, the operator tag never appearing on the About page, a healthy relay being reported as down, and the Matrix chat link not opening. All are small, self-contained fixes so a tor-only node comes up clean without hand-tuning.

    Fixed

    The warrant canary no longer leaks over clearnet on a tor-only node. The canary auto-detects tor-only from the instance's origin, but setup accepted a free-text URL — so an origin that wasn't the node's real .onion silently disabled tor-only routing, and the freshness fetches (Blurt head, BTC head, news) went out over clearnet, revealing the node's IP. Two fixes close this: setup now defaults the instance URL to the node's own configured public origin (the .onion on a tor-only box), so auto-detection fires; and on a tor-only node the generator now auto-selects one of the node's own hidden .onion Blurt RPCs for the chain-head proof, so it fetches over Tor natively instead of pushing a clearnet RPC through a Tor exit (which those RPCs' firewalls reject). A tor-only node now signs a leak-free canary with no manual configuration.

    The operator tag now shows on the About page. The page read the operator tag from the build-time verify.json, so setting the tag in the settings editor and restarting the indexer never changed the displayed value — it only updated after a full frontend rebuild. The page now reads the tag from the live /v1/instance endpoint (falling back to the signed verify.json), so a tag change appears as soon as the indexer restarts.

    /v1/health no longer reports a healthy relay as down. The relay-reachability probe tried the configured URL, the host's own IP addresses, and the container bridge gateway — but not loopback, unless the configured URL already was loopback. On a bare-metal node whose relay binds 127.0.0.1, an empty or differently-pointed RELAY_HEALTH_URL made a perfectly healthy relay read as down, disagreeing with morphit-ops health and a direct curl. The probe now always tries 127.0.0.1 as well (preserving the configured port and path), so a local relay is always found.

    The Matrix chat link opens in a browser. The About page linked the group chat with the bare matrix: URI scheme, which most browsers have no handler for, so the link silently did nothing. It now uses the universal matrix.to link (the same one used elsewhere in the app); the room alias stays in the URL fragment, which browsers don't send to the matrix.to server, and the room is public.

    A tor-only node no longer falsely accuses a clearnet peer of a fee-redirection "mismatch". A tor-only node reaching a clearnet peer's /v1/instance over a Tor exit often gets a firewall challenge page instead of JSON. The probe treated any unreadable response as a "mismatch" — which is a fee-redirection accusation shown against a perfectly healthy instance. An unreadable response is now correctly classified as unreachable, not a mismatch. The actual fee-redirection checks (relay account and treasury) still run on well-formed responses, so nothing that could redirect fees slips through.

    Notes

    • No database migration in this release.
    • A related architectural limitation remains (a larger change for a future release): a peer's hidden (.onion/.i2p) addresses live only inside its /v1/instance response, not in its on-chain registration — so a tor-only node has no Tor-native way to reach a clearnet peer at all. This release stops the false accusation (above); fully probing clearnet peers from a tor-only node needs alt-network addresses added to the registration op.
    • Everything from v1.12.10 (the tor-only clearnet-probe fix, the /v1/health operational-snapshot resilience, and the federation mismatch-while-syncing suppression) is included.
    Downloads
  • v1.12.10 4b12d403d5

    Morphit v1.12.10
    All checks were successful
    morphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 50s
    morphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 39s
    morphit-ci / Integration tests (real Postgres 16) (push) Successful in 41s
    morphit-ci / ansible-lint (playbook quality gate) (push) Successful in 16s
    morphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 30m8s
    morphit-release / Build + publish release tarball (push) Successful in 36m21s
    Stable

    agorise released this 2026-08-19 16:43:14 +00:00 | 64 commits to main since this release

    Signed by agorise
    GPG key ID: 53524E1F1017EB9C

    Morphit v1.12.10

    Theme: closing the last tor-only leaks and false alarms. This release stops a tor-only node from probing clearnet Blurt RPC endpoints in its stats page (which would reveal the node's real IP), fixes the /v1/health operational block so it stops reporting a healthy relay and host as down, stops a still-syncing node from falsely flagging a healthy peer as a fee-redirection "mismatch", and fixes the warrant-canary setup so it completes on a root-installed node instead of aborting. It also adds operator tooling: an indexer-database snapshot bootstrap (sync a new box in minutes from your own synced box) and the on-chain chain_snapshot_v1 anchor for publishing a canonical block_log snapshot.

    Fixed

    A tor-only node no longer probes clearnet RPC endpoints in the stats page. The "RPC endpoints" card refreshes by actively probing every node in its list — but that list always included the six clearnet Blurt RPCs, even on a tor-only node whose clearnet pool is empty. On a tor-only box that meant the indexer was still reaching those six operators over clearnet, revealing the node's real IP — the same class of exposure v1.12.9 closed for chain syncing. The probe list now includes the clearnet nodes only when the instance actually syncs over clearnet; a tor-only node probes and displays only its hidden (Tor/I2P) endpoints, matching what /v1/health already reports. Clearnet nodes are unchanged.

    /v1/health no longer reports a healthy relay and host as down. The operational block (relay reachability, host CPU/memory/disk, IPFS seeding) sampled all of its inputs in a single all-or-nothing pass, so one probe failing — or a single sample never completing — left the entire block frozen at its "unknown / down / not sampled" defaults, disagreeing with what morphit-ops health showed. Each input is now sampled independently: a failing probe keeps its previous value and never blanks the others, and a stalled refresh can no longer wedge the block permanently.

    A still-syncing node no longer falsely flags a healthy peer as "mismatch". The federation directory flags a peer whose advertised fee-treasury addresses differ from the canonical ones (a fee-redirection defense). But a node that is still catching up has an incomplete view of the chain, so its canonical-treasury baseline can be wrong — causing it to falsely accuse a healthy, fully-synced instance. The treasury check is now withheld while the local node is still syncing (it re-engages the moment the node is caught up). The relay-account and response-shape checks are unaffected, so a synced node's fee-redirection defense is unchanged.

    The warrant-canary setup completes on a root-installed node instead of aborting. On a root-installed /opt/morphit, canary setup run as a non-root operator died at a "permission denied" writing the public key into the root-owned source tree — before it ever wrote the refresh script or armed the weekly timer, leaving the node with no canary. Setup now stages the signed canary and public key in the operator-writable ~/.morphit/canary/, only reading the source tree for the template, and still publishes the artifacts into the served build directory. Say yes once and the canary signs, publishes, and arms its weekly refresh with no permission wall.

    Added

    Indexer-database snapshot bootstrap. A new node can sync in minutes instead of days by restoring an already-synced indexer's Postgres database and catching up only the small gap — which matters most for a tor-only node that can only sync over hidden RPC. snapshot-export.ts produces a portable snapshot (database dump plus a manifest); snapshot-bootstrap.ts verifies compatibility (exact chain-id match, schema not newer than this build, Postgres not newer than the host — all fail closed), requires an explicit trust acknowledgement, refuses to clobber a populated database, restores, and confirms. This is safe only between an operator's own boxes — you are trusting your own derived state. A public, signed snapshot is a separate decision and is not included here.

    On-chain chain_snapshot_v1 anchor. The publish side for a canonical Blurt block_log snapshot: @morphit posts a custom_json op pointing at the snapshot (IPFS CID, SHA-256, height, size, blurtd version, optional IPNS name and mirror URL), exactly the way releases are anchored. The block_log is the raw, self-verifying chain, so a node that fetches it re-checks every block on import — making it a zero-trust public artifact. Includes the op format + validator and a laptop broadcaster (dry-run by default).

    A sync profiler and a tor-only node doctor. apps/indexer/scripts/sync-profile.ts measures where initial sync time actually goes (fetch vs. commit vs. apply), so slow syncs can be diagnosed rather than guessed at. ops/morphit-node-doctor.sh checks a node end-to-end — clearnet-leak status, stray processes, hidden transports, canary, sync — and safely auto-fixes the clearnet pool on a tor-only box.

    Notes

    • No database migration in this release.
    • The snapshot bootstrap, the chain_snapshot_v1 broadcaster, and the tor-only routing added here are shape- and smoke-validated; the database dump/restore and the on-chain publish need a live run on real infrastructure to validate end-to-end (there is no synced database or signing key in CI).
    • Everything from v1.12.9 (tor-only hidden-only RPC, the canary routing over Tor, and web-push configuration on tor-only nodes) is included.
    Downloads
  • v1.12.9 59da8e68ea

    Morphit v1.12.9
    All checks were successful
    morphit-ci / TypeScript typecheck (sweep all workspaces) (push) Successful in 47s
    morphit-ci / apps/web svelte-check (svelte-kit sync + svelte-aware tsc) (push) Successful in 38s
    morphit-ci / Integration tests (real Postgres 16) (push) Successful in 40s
    morphit-ci / ansible-lint (playbook quality gate) (push) Successful in 15s
    morphit-ci / Smoke suite (run-smokes.sh, triple-pulse) (push) Successful in 29m44s
    morphit-release / Build + publish release tarball (push) Successful in 36m13s
    Stable

    agorise released this 2026-08-18 15:35:12 +00:00 | 65 commits to main since this release

    Signed by agorise
    GPG key ID: 53524E1F1017EB9C

    Morphit v1.12.9

    Theme: a tighter tor-only node. This release stops a tor-only indexer from reaching clearnet Blurt RPC (which would reveal the node's real IP to those RPC operators), fixes web-push configuration on tor-only nodes so the relay never crash-loops over an invalid VAPID subject, and makes the warrant-canary restore itself automatically on upgrade for appliance/Ansible installs.

    Fixed

    Tor-only indexers now read the chain over hidden services only. A tor-only node was still reaching six clearnet Blurt RPC endpoints, exposing its real IP to those operators — the exact exposure tor-only exists to prevent. The indexer now empties its clearnet RPC pool on tor-only and reads purely over the hidden-service (.onion / .b32.i2p) pool; the "at least one chain source" requirement is now enforced over the combined local + clearnet + hidden pool, so a hidden-only configuration is valid while a truly source-less one is still rejected. Clearnet nodes are unchanged.

    Web push no longer misconfigures itself on tor-only nodes. The VAPID subject was derived as https://<domain>, which is a domain-less, invalid https:// on a tor-only node. It now derives a mailto: from the operator's contact URL when that is a mailto:, and otherwise stays empty — which cleanly disables push instead of producing an invalid subject. Clearnet nodes still derive https://<domain> as before. (The always-on in-tab ambient notifications — tab title and favicon unread badge — already work on tor-only regardless of push.)

    The warrant canary restores itself on upgrade for appliance/Ansible installs. An upgrade could leave the canary missing until the next weekly refresh on boxes provisioned with a system morphit-canary.service (rather than a ~/.morphit refresh script). The upgrade now triggers that service directly — the exact unit the weekly timer fires — and falls back to the home-directory refresh script for interactive installs. Either path restores the canary immediately with no manual step.

    Build-integrity manifests are now byte-identical regardless of deploy path. The .shipped build marker is excluded from /verify.json hashing (it's a build-system signal, not a served asset), so an instance that re-ran the manifest step and one that kept the shipped manifest now produce identical verify.json files.

    Small UI fix. On the "about this instance" page, a 56-character .onion origin now wraps instead of overflowing its cell.

    The warrant-canary refresh no longer reaches clearnet on a tor-only node. The weekly canary's freshness-proof fetches (Blurt chain-head, Bitcoin head, news headline) were going directly to clearnet endpoints on a tor-only node, which could reveal the node's real IP to those third parties — the same class of exposure this release closes for the indexer. On tor-only, all three now route through the co-located Tor SOCKS proxy (DNS resolved proxy-side, so nothing leaks), reaching the same freshness sources through a Tor exit. It is fail-safe: if the Tor proxy is down the canary degrades or holds rather than ever falling back to a direct clearnet connection. Clearnet nodes are byte-identical to before.

    Notes

    • No database migration in this release.
    • The tor-only privacy work in this release (indexer hidden-only RPC + the canary routing over Tor) is code-complete but its live Tor routing was validated by shape/smoke, not end-to-end in CI — confirm on a real tor-only box that the canary's route = tor-only (SOCKS …) and the indexer reads only over hidden endpoints. Details in docs/AUDIT-cp760-v1.12.9-DELTA-DEEP-DEEP.md.
    • Everything from v1.12.8 (the build-integrity banner bootstrap fix) is included.
    Downloads