Issue 129 is resolved: a workstation trusts the mesh, and stops when told to

Registered ca-trust from the catalogue — it was merged and had never been
registered, which is why "assign it to one machine" had no module to name
— assigned it to the workstation, and verified.

Verified in the form ADR 0147 prescribes, against the authority's own API
so the handshake needs nothing else in the mesh to be right: 200, issuer
Mesh Internal CA, Verify return code 0. Four routed internal names verify
too, and `git ls-remote https://…` works, which is the consequence the
report named.

Removal exercised for the first time. Unassign and push removes the
anchor, empties the trust store of the mesh's authority, and returns the
plain client to the original error; assigning again restores it. That is
the half 0147 claimed and nothing had shown.

One thing it found that is not in the module: removal works only because
the host removes the service before the script. Stopping the unit is what
deletes the certificate and refreshes the bundles, and it needs the script
to still exist. The symmetry rests on an ordering nothing states.

0147's "written, and not yet run" now carries a progressive insight
saying it has run, where, and that it ran on one machine of four.
This commit is contained in:
2026-09-30 02:18:21 +02:00
parent 76fbe323ea
commit 1f72e82b84
3 changed files with 117 additions and 2 deletions
@@ -1,7 +1,8 @@
---
status: diagnosing
status: resolved
opened: 2026-09-26
located-in: [mesh-catalog ca-trust]
located-in: [mesh-catalog modules/ca-trust]
fixed-by: the ca-trust module registered from the catalogue and assigned to a workstation; verified in both directions 2026-09-30 (02-resolution.md)
---
# 129 — nothing makes a machine trust the mesh's own certificate authority
@@ -0,0 +1,86 @@
# 129 — resolved: the workstation trusts the mesh, and stops when told to
*Done and measured on the machine, 2026-09-30.*
## What was done
Three steps, not the one the plan expected — the module was merged and had never been registered
(see [the diagnosis](01-diagnosis.md)):
1. **Registered** `ca-trust` from the catalogue. No artifact to build: it declares a directory, a
script, a unit and a service, and no image.
2. **Assigned** it to the workstation the issue was opened on, and pushed.
3. **Verified** with a plain client, then **unassigned and pushed again** to exercise removal, then
assigned and pushed once more.
The host's own account of arriving:
```
created ca-trust.state (/var/lib/ca-trust)
created ca-trust.anchor (/var/lib/ca-trust/anchor)
created ca-trust.unit (/etc/systemd/system/mesh-ca-trust.service)
updated ca-trust.trust (mesh-ca-trust.service): boot disabled to enabled, stopped to running
```
## It works, by the check the report asked for
The report's own reproduction, with no flags and nothing installed by hand:
```
$ curl -sS -o /dev/null -w '%{http_code}' https://git.novox.internal/
200
$ openssl s_client -connect git.novox.internal:443 -servername git.novox.internal
issuer=O=Mesh Internal CA, CN=Mesh Internal CA Intermediate CA
Verify return code: 0 (ok)
$ trust list | grep -A2 Mesh
label: Mesh Internal CA Root CA
trust: anchor
category: authority
```
Four internal names, all verifying: `git` 200, `umami` 200, `keycloak` 302, `drive` 302. Before this,
every one of them was `curl: (60) … unable to get local issuer certificate (20)`.
**And the consequence the report named specifically**: git over HTTPS to the mesh's forge, which it said
had forced the working clone URL to be ssh-only.
```
$ git ls-remote https://git.novox.internal/novox/hq.git HEAD
76fbe323ea3401fcdadbf500c61bd3fa5a0a8603 HEAD
```
## Removal is symmetric, which nothing had ever shown
[ADR 0147](../../02-DECISIONS/0147-a-module-anchors-the-meshs-authority.md) says the module anchors the
authority *and takes it away again*. That half had never run. Unassigning and pushing:
```
removed ca-trust.trust (mesh-ca-trust.service)
removed ca-trust.unit (/etc/systemd/system/mesh-ca-trust.service)
removed ca-trust.anchor (/var/lib/ca-trust/anchor)
removed ca-trust.state (/var/lib/ca-trust)
```
Then: the anchor file gone, `trust list` naming no authority of the mesh's, and the plain client back to
`unable to get local issuer certificate (20)`. A machine that leaves the mesh stops trusting it, as the
record claims.
**The order is what makes it work, and is worth saying.** The service is removed *first*, so systemd
runs the unit's `ExecStop` — which is what deletes the certificate and refreshes the bundles — while the
script it calls still exists. Had the script or the state directory gone first, stopping the unit would
have had nothing to run, and the anchor would have been left behind with nothing declaring it. Nothing
in the module says this; it is the host's removal order that makes the module's symmetry real.
## What this leaves
- **One machine, not four.** `novox`, `g14` and `ace` still trust nothing of the mesh's. The report's
reasoning — that being on the private network is what makes a machine one that speaks to the mesh's
names — argues for all of them, and ADR 0147 is written for a module assigned per machine rather than
a fact carried to every machine on the network. Whether it should instead arrive the way the roster
and the registry trust do is a real question and is not this record's to answer.
- **`service-manager` reports `degraded` on this machine** and the module ran anyway. Worth knowing that
the capability gate passes on a degraded service manager, since a module whose whole delivery is a
unit is the kind that would be worst served by one.
- **The predecessor's authority is still in the trust store**, beside the mesh's now rather than instead
of it. The report notes that it cannot be retired while anything on the machine speaks TLS to a mesh
name; that is no longer true here, and retiring it is its own piece of work.