Delete go/overlay: no importer is left; the package list, notInSDK and seat-names follow (S-7, ADR 0634 §5; issue 1966)
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -1,65 +0,0 @@
|
||||
package catalogue_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/overlay"
|
||||
)
|
||||
|
||||
// The manifests the control plane actually ships, resolved.
|
||||
//
|
||||
// Written because the earlier tests built their own manifests and passed while the real one was
|
||||
// missing a claim — a whole mechanism could have been absent from what ships and every test would
|
||||
// still have been green.
|
||||
|
||||
func provided(t *testing.T) map[string]catalogue.Manifest {
|
||||
t.Helper()
|
||||
out := map[string]catalogue.Manifest{}
|
||||
for _, raw := range []map[string]any{
|
||||
overlay.Manifest(),
|
||||
} {
|
||||
b, err := json.Marshal(raw)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
m, err := catalogue.Decode(b)
|
||||
if err != nil {
|
||||
t.Fatalf("a manifest this control plane ships is not valid: %v", err)
|
||||
}
|
||||
out[m.Module] = m
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func TestTheControlPlaneShipsNoNetworkingBundle(t *testing.T) {
|
||||
// ADR 0226: one module for the one private network. A bundle shipped beside it again would be
|
||||
// a second name every machine carries for the same thing.
|
||||
shipped := provided(t)
|
||||
if len(shipped) != 1 {
|
||||
t.Fatalf("the control plane ships %d modules, want only %s", len(shipped), overlay.Name)
|
||||
}
|
||||
if _, ok := shipped["networking"]; ok {
|
||||
t.Fatal("the retired networking bundle is shipped again")
|
||||
}
|
||||
}
|
||||
|
||||
// The names-need-addressing test went with the names module: names are a fact now, and a machine
|
||||
// the mesh cannot place is simply left out of the file (facts_test.go) — which is the same
|
||||
// protection, enforced where the file is written rather than by a provision refusing.
|
||||
|
||||
func withTailscale(shelf map[string]catalogue.Manifest) map[string]catalogue.Manifest {
|
||||
out := map[string]catalogue.Manifest{}
|
||||
for k, v := range shelf {
|
||||
out[k] = v
|
||||
}
|
||||
// Deliberately without name-resolution of its own, which is the case that used to install
|
||||
// both VPNs: the names then needed the mesh's addressing, and only WireGuard has it.
|
||||
out["tailscale"] = catalogue.Manifest{
|
||||
Module: "tailscale", Version: "1",
|
||||
Provides: catalogue.Offers(overlay.Requirement),
|
||||
Claims: []catalogue.Claim{{Name: overlay.TheNetwork, Scope: catalogue.ScopeNode}},
|
||||
}
|
||||
return out
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
// Package overlay is the private network's names and its manifest: the module the mesh provides for itself, the
|
||||
// requirement and seat it answers, the interface's name and files, and the mesh's internal names. Its generator, the
|
||||
// peer graph and the declaration it renders are the node-engine's own (novox/hq ADR 0593 §1, §7), in mesh-host's
|
||||
// internal/overlay.
|
||||
package overlay
|
||||
@@ -1,39 +0,0 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Names are how one node reaches another by name rather than by address.
|
||||
//
|
||||
// novox/hq 08-connectivity: what the host receives is the resolver's configuration, as files,
|
||||
// listing every peer's internal name and overlay address. Computed centrally for the same reason
|
||||
// the peer graph is — it needs every node at once.
|
||||
|
||||
// SuffixVar lets a mesh choose what its internal names end in.
|
||||
const SuffixVar = "MESH_INTERNAL_SUFFIX"
|
||||
|
||||
// DefaultSuffix is `.internal`, which IANA reserved for exactly this in 2024. A name under it can
|
||||
// never collide with a public one, so an internal name that leaks into a public resolver fails
|
||||
// rather than reaching a stranger's machine.
|
||||
const DefaultSuffix = "internal"
|
||||
|
||||
// Suffix is what internal names end in.
|
||||
func Suffix() string {
|
||||
if v := strings.TrimSpace(os.Getenv(SuffixVar)); v != "" {
|
||||
return strings.TrimPrefix(v, ".")
|
||||
}
|
||||
return DefaultSuffix
|
||||
}
|
||||
|
||||
// nodeName is what a node may be called, so that it can also be a hostname.
|
||||
var nodeName = regexp.MustCompile(`^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$`)
|
||||
|
||||
// InternalName is a node's name inside the mesh.
|
||||
func InternalName(node string) string { return node + "." + Suffix() }
|
||||
|
||||
// **What remains of a larger file.** The rest wrote /etc/hosts, which the controller no longer
|
||||
// writes at all (novox/hq ADR 0199): the mesh's resolver answers these names. The naming stays here, because several things compose a node's internal name and one of them
|
||||
// writing the suffix differently would be a name nothing answers to.
|
||||
@@ -1,79 +0,0 @@
|
||||
package overlay
|
||||
|
||||
// The private network as a module rather than as code beside the module system.
|
||||
//
|
||||
// A machine's peer list is derived from every other machine, so it differs on each one and
|
||||
// changes when any of them changes — there is nothing that could be written in a manifest. So the
|
||||
// module says its resources are computed, and this computes them.
|
||||
//
|
||||
// What that buys, beyond one mechanism instead of two: **a machine is on the private network
|
||||
// because it was assigned the module.** Before this, every machine with a key and an address was
|
||||
// on it, and there was no way to say a machine should stay off.
|
||||
//
|
||||
// It is worth saying what is *not* here, because networking looks like it should be foundational.
|
||||
// The host needs none of this. It has an address and a route to the broker before the mesh exists
|
||||
// — that is the machine's own networking — and the broker's address is carried in the enrolment
|
||||
// token rather than resolved. So the private network is something the mesh installs on top, like
|
||||
// anything else, and a node without it is an ordinary node that nothing reaches directly.
|
||||
|
||||
// What a module asks for when it needs machines to reach each other. **This is the name that
|
||||
// matters** — WireGuard is one way to answer it, and naming the requirement after the answer is
|
||||
// how a mesh ends up unable to have a second one.
|
||||
const Requirement = "private-network"
|
||||
|
||||
// Name is the module that answers it with WireGuard.
|
||||
//
|
||||
// **It writes no names.** A machine's mesh names are answered by the mesh's one resolver (novox/hq
|
||||
// ADR 0194), and /etc/hosts is the file of one module, the holder of `node-hostname` (ADR 0199,
|
||||
// ADR 0223): the controller writes into no file another seat's holder owns. If the mesh ever needs a line there, it
|
||||
// asks that holder to register it. This module asked for a `node-names` fact written into /etc/hosts
|
||||
// until 2026-10-05; the host gives that region back at the first push without it.
|
||||
const Name = "mesh-wireguard"
|
||||
|
||||
// Addressing is the mesh handing out addresses on the private network itself.
|
||||
//
|
||||
// The mesh's resolver answers names from it, which is why it requires this rather than a private
|
||||
// network in general. A different VPN that hands out its own addresses would come with its own
|
||||
// names — the mesh has nothing to answer about a machine whose address it did not choose.
|
||||
const Addressing = "mesh-addressing"
|
||||
|
||||
// TheNetwork is what a machine can only have one of.
|
||||
//
|
||||
// Providing a private network is not the singular part — a machine could reasonably run two VPNs
|
||||
// for two different purposes. Being **the** one the mesh runs over is singular, and without
|
||||
// saying so a person who chose a different VPN can still end up with this one dragged back in by
|
||||
// something that needed the mesh's own addresses. Which is exactly what happened, once.
|
||||
const TheNetwork = "the-private-network"
|
||||
|
||||
// **A resolver's data went the same way as the names.** Two constants used to sit here — a
|
||||
// `mesh-resolver` module that would write the machines as wildcards, and a `resolver-data`
|
||||
// requirement a daemon would ask for. Nothing ever provided or consumed either: a module that
|
||||
// answers names asks for the `node-zones` fact in its own manifest (catalogue.FactsInto) and
|
||||
// requires Addressing, since the file is made of the mesh's addresses and means nothing off the
|
||||
// network. A requirement nothing provides is refused at resolution, so leaving the names here
|
||||
// would only have documented a mechanism that does not exist.
|
||||
|
||||
// Manifest is the module the mesh provides for itself.
|
||||
//
|
||||
// It ships with the control plane rather than coming from a repository, because the thing that
|
||||
// computes it ships with the control plane. That is the only way it is unusual: it is assigned,
|
||||
// unassigned, resolved and settled exactly like a module somebody wrote.
|
||||
func Manifest() map[string]any {
|
||||
return map[string]any{
|
||||
"module": Name,
|
||||
"version": "1",
|
||||
"computed": Name,
|
||||
"provides": []string{Requirement, Addressing},
|
||||
"claims": []map[string]any{{"name": TheNetwork, "scope": "node"}},
|
||||
}
|
||||
}
|
||||
|
||||
// Interface is what the private network is called on a machine, and where the node's own key
|
||||
// lives. A constant rather than a setting: two nodes disagreeing about the name would produce a
|
||||
// mesh where each is configured correctly and nothing meets.
|
||||
const (
|
||||
Interface = "mesh0"
|
||||
ConfigPath = "/etc/wireguard/" + Interface + ".conf"
|
||||
Unit = "wg-quick@" + Interface
|
||||
DefaultKeyPath = "/var/lib/mesh-host/overlay.key"
|
||||
)
|
||||
@@ -1,30 +0,0 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
)
|
||||
|
||||
// The private network's claim is a seat the mesh defines (novox/hq ADR 0110).
|
||||
//
|
||||
// Checked here because this is where the manifest is composed: it ships with the control plane and
|
||||
// has no module.json for a test reading the catalogue to find. Parsed with the real parser, so a
|
||||
// set that forgot this seat refuses the control plane's own module here rather than on a machine.
|
||||
func TestThePrivateNetworksClaimIsASeatTheMeshDefines(t *testing.T) {
|
||||
for _, composed := range []map[string]any{Manifest()} {
|
||||
raw, err := json.Marshal(composed)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Decoded here; the indexer's judge judges it (mesh-delivery's judge tests hold it to every rule).
|
||||
if _, err := catalogue.Decode(raw); err != nil {
|
||||
t.Errorf("%s, composed by the control plane, does not decode: %v", composed["module"], err)
|
||||
}
|
||||
}
|
||||
seat, defined := catalogue.SeatNamed(TheNetwork)
|
||||
if !defined || seat.Scope != catalogue.ScopeNode {
|
||||
t.Fatalf("%s is not a node seat the mesh defines: %+v", TheNetwork, seat)
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package overlay
|
||||
|
||||
import (
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/seatlist/seatlisttest"
|
||||
)
|
||||
|
||||
// The seats the tests judge against are given to catalogue as a host gives the ones it read from the bus (ADR 0635 §1).
|
||||
func init() { catalogue.UseSeats(catalogue.SeatsFromDefinitions(seatlisttest.Definitions())) }
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
var meshSDKPackages = []string{
|
||||
".", "announce", "announcetest", "buscalls", "buscompose", "busstate", "busretry", "calladdress", "catalogue",
|
||||
"declaration", "forgekey", "health", "internal/beside", "keys", "kvlimit", "membership", "motion",
|
||||
"objectlink", "outward", "overlay", "pernode", "process",
|
||||
"objectlink", "outward", "pernode", "process",
|
||||
"sdkversion", "seal", "seatdef", "seatlist", "seatlist/seatlisttest", "testbus", "views", "views/viewstest",
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ var clientSeats = []string{"operator-channel", "mesh-vault", "node-engine", "npm
|
||||
var moduleWord = regexp.MustCompile(`\bmesh-(?:delivery|grants|vault|host|config|provisioner|broker|knowledge|enrolment)\b[-a-z]*|\b(?:indexer|assigner|teller|watchman|checker|builder)(?:-views|_read_)`)
|
||||
|
||||
// notInSDK are the packages that moved to a seat's client or contract (ADR 0627 §1, §4) and may not come back.
|
||||
var notInSDK = []string{"asks", "asker", "publish", "composer", "parts", "provider", "handacts", "channel", "provisions", "buildstep", "delivery"}
|
||||
var notInSDK = []string{"asks", "asker", "publish", "composer", "parts", "provider", "handacts", "channel", "provisions", "buildstep", "delivery", "overlay"}
|
||||
|
||||
// untilTheJoin is what ADR 0627 still moves at the group's join, each `<file>: <what>`, naming what the checks below
|
||||
// would refuse; it only shrinks. The vault module's name in delivery stays past this milestone's pin
|
||||
|
||||
Vendored
-1
@@ -32,5 +32,4 @@ health/findings.go: mesh-conditions
|
||||
health/findings.go: mesh-healers
|
||||
health/findings.go: mesh-self-check
|
||||
internal/beside/beside.go: mesh-catalog
|
||||
overlay/overlay.go: the-private-network
|
||||
seatlist/seatlist.go: mesh-catalog
|
||||
|
||||
Reference in New Issue
Block a user