Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
efdcc9daef | ||
|
|
f18ec031c4 | ||
|
|
9d67813829 | ||
|
|
f82e0b77b4 | ||
|
|
a74f9db508 | ||
|
|
9c9d03691b |
@@ -54,40 +54,16 @@ func TestRouteProxyKeepsItsPublicAccountDirectory(t *testing.T) {
|
|||||||
if slices.Contains(m.Requires, "acme-ca") {
|
if slices.Contains(m.Requires, "acme-ca") {
|
||||||
t.Fatal("route-proxy still asks for acme-ca; the public issuer is its own fact (ADR 0226)")
|
t.Fatal("route-proxy still asks for acme-ca; the public issuer is its own fact (ADR 0226)")
|
||||||
}
|
}
|
||||||
// As a build would leave it: each artifact a container names resolved to an image. Which image does not matter to
|
// The tree read inlines the template the manifest names, a literal with nothing to fill, so this is what it writes.
|
||||||
// the file checked here. An archive resource carries no image: it unpacks a bundle.
|
env := resourceNamed(m.Resources, "acme-env")
|
||||||
for _, res := range m.Resources {
|
|
||||||
if res["type"] == "archive" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if artifact, ok := res["artifact"].(string); ok {
|
|
||||||
delete(res, "artifact")
|
|
||||||
res["image"] = "registry.invalid/route-proxy/" + artifact +
|
|
||||||
"@sha256:1111111111111111111111111111111111111111111111111111111111111111"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
r := catalogue.Resolution{
|
|
||||||
Node: "anchor",
|
|
||||||
Modules: []catalogue.Manifest{m},
|
|
||||||
Needs: []catalogue.Needed{{
|
|
||||||
Name: "internal-acme-ca", From: "home", At: "home.internal", For: "route-proxy",
|
|
||||||
Serves: map[string]any{"port": float64(9000), "path": "/acme/acme/directory", "roots": "/roots.pem"},
|
|
||||||
}},
|
|
||||||
}
|
|
||||||
// Its own broker credential, sealed as the mesh would; what it is does not matter here.
|
|
||||||
out, err := r.Declaration(catalogue.Rendering{Needed: map[string]map[string]string{"route-proxy": {"broker": "sealed"}}})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("route-proxy could not be composed for a machine: %v", err)
|
|
||||||
}
|
|
||||||
env := resourceNamed(out, "route-proxy.acme-env")
|
|
||||||
if env == nil {
|
if env == nil {
|
||||||
t.Fatalf("nothing writes the public issuer's environment: %v", out)
|
t.Fatalf("nothing writes the public issuer's environment: %v", m.Resources)
|
||||||
}
|
}
|
||||||
if got, _ := env["content"].(string); got != renderedBeforeTheFold {
|
if got, _ := env["content"].(string); got != renderedBeforeTheFold {
|
||||||
t.Fatalf("acme.env changed, which moves the proxy's account and reorders every certificate:\ngot %q\nwant %q",
|
t.Fatalf("acme.env changed, which moves the proxy's account and reorders every certificate:\ngot %q\nwant %q",
|
||||||
got, renderedBeforeTheFold)
|
got, renderedBeforeTheFold)
|
||||||
}
|
}
|
||||||
if resourceNamed(out, "route-proxy.bound-acme-ca") != nil {
|
if resourceNamed(m.Resources, "bound-acme-ca") != nil {
|
||||||
t.Error("a binding to acme-ca is still written")
|
t.Error("a binding to acme-ca is still written")
|
||||||
}
|
}
|
||||||
var trust string
|
var trust string
|
||||||
|
|||||||
@@ -154,70 +154,33 @@ func TestARouteWithNoInternalNameGetsNoAlias(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A route is dialled where the machine publishes its module's endpoint, as the module's declaration publishes it (issue
|
// A route is dialled at the machine port its plan entry carries (issue 774, research 072 row 34; 2026-10-31: gitea's
|
||||||
// 774, research 072 row 34; 2026-10-31: gitea's 3000, published at 20000, and grafana's 3000 on another machine,
|
// 3000, published at 20000, and grafana's 3000 on another machine, published at 20012, answered 502): over loopback
|
||||||
// published at 20012, answered 502): over loopback beside the proxy, which is the only thing that works without a
|
// when the plan is the one of this proxy's own node, which is the only thing that works without a private network, and
|
||||||
// private network, and at its machine's address otherwise. Each plan is composed by the SDK as the seat
|
// at the address the entry gives for its machine otherwise. The plans here are written as the seat mesh-provisioner
|
||||||
// mesh-provisioner composes it, its ports as compose's portsFor gives them (the placement's for a port the mesh may
|
// carries them; that the port is the placement's and not the software's own is the composition's, proved by the
|
||||||
// move, the manifest's own otherwise), and read as this proxy reads it: the live shapes the old proxy served alike.
|
// node-engine's composer, not here.
|
||||||
func TestAComposedPlanIsDialledWhereTheMachinePublishesIt(t *testing.T) {
|
func TestAPlanEntryIsDialledAtTheMachinePortItCarries(t *testing.T) {
|
||||||
proxy := catalogue.Manifest{Module: "route-proxy", Version: "1",
|
|
||||||
Provides: []catalogue.Offer{{Name: "route", Scope: catalogue.ScopeMesh, AnsweredBy: catalogue.AnsweredByHelper}}}
|
|
||||||
world := catalogue.World{Offered: map[string][]catalogue.Provider{
|
|
||||||
"route": {{Node: "anchor", At: "anchor.internal", Module: "route-proxy"}}}}
|
|
||||||
for _, c := range []struct {
|
for _, c := range []struct {
|
||||||
name, node, module string
|
name, node, module, at string
|
||||||
port int // the endpoint's port, as listens says it
|
port int
|
||||||
published []any // the container's ports; nil for the host's network
|
target string
|
||||||
placed map[int]int // what mesh-placement holds for the module
|
|
||||||
target string
|
|
||||||
}{
|
}{
|
||||||
{"beside the proxy, moved by the placement (gitea)", "anchor", "gitea", 3000, []any{"3000"}, map[int]int{3000: 20000},
|
{"beside the proxy (gitea)", "anchor", "gitea", "", 20000, "http://127.0.0.1:20000"},
|
||||||
"http://127.0.0.1:20000"},
|
{"beside the proxy, though the entry says an address (mailu)", "anchor", "mailu", "anchor.internal", 7080, "http://127.0.0.1:7080"},
|
||||||
{"on another machine, moved by the placement (grafana)", "home", "grafana", 3000, []any{"3000"},
|
{"on another machine (grafana)", "home", "grafana", "home.internal", 20012, "http://home.internal:20012"},
|
||||||
map[int]int{3000: 20012}, "http://home.internal:20012"},
|
{"on another machine, a bare port (influxdb)", "home", "influxdb", "home.internal", 8086, "http://home.internal:8086"},
|
||||||
{"a bare port the placement holds none for (influxdb)", "home", "influxdb", 8086, []any{"8086"}, nil,
|
|
||||||
"http://home.internal:8086"},
|
|
||||||
{"a fixed mapping (mailu 7080:80)", "anchor", "mailu", 7080, []any{"25", "7080:80"}, nil, "http://127.0.0.1:7080"},
|
|
||||||
{"a fixed mapping the placement names another port of (photos 9102:9000)", "anchor", "photos", 9102,
|
|
||||||
[]any{"9102:9000"}, map[int]int{9000: 20011}, "http://127.0.0.1:9102"},
|
|
||||||
{"the host's network (home-assistant)", "anchor", "home-assistant", 8123, nil, nil, "http://127.0.0.1:8123"},
|
|
||||||
} {
|
} {
|
||||||
container := map[string]any{"type": "container", "name": c.module, "image": "x"}
|
values, _ := json.Marshal(map[string]any{"name": c.module + ".example.org", "port": c.port})
|
||||||
if c.published != nil {
|
// The form as the seat carries it (version 1): written here, so what the proxy decodes is the shape, not a helper.
|
||||||
container["ports"] = c.published
|
contributed, err := json.Marshal(catalogue.ContributedForm{V: catalogue.ContributedVersion, At: c.at,
|
||||||
} else {
|
Each: []catalogue.ContributedOne{{Values: values}}})
|
||||||
container["network"] = "host"
|
|
||||||
}
|
|
||||||
module := catalogue.Manifest{Module: c.module, Version: "1", Requires: []string{"route"},
|
|
||||||
Listens: []catalogue.Listening{{Name: "web", Port: c.port, Protocol: "tcp", From: "mesh"}},
|
|
||||||
Contributes: map[string]map[string]any{"route": {"label": c.module, "endpoint": "web"}},
|
|
||||||
Resources: []map[string]any{container}}
|
|
||||||
node := catalogue.Node{Name: c.node, At: c.node + ".internal", PublicDomain: "example.org",
|
|
||||||
Capabilities: map[string]bool{"container-runtime": true}}
|
|
||||||
r, err := catalogue.Resolve(map[string]catalogue.Manifest{module.Module: module, proxy.Module: proxy},
|
|
||||||
[]string{module.Module}, node, world)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: %v", c.name, err)
|
t.Fatalf("%s: %v", c.name, err)
|
||||||
}
|
}
|
||||||
r.Account = "op"
|
value, err := provisions.EncodePlan(provisions.Plan{Node: c.node, Module: c.module, Plan: catalogue.Plan{
|
||||||
for i, n := range r.Needs {
|
Provisions: []catalogue.PlanProvision{{Provision: contract.Provision, Provider: "anchor",
|
||||||
r.Needs[i].AnsweredByHelper = n.Name == "route" // as the plan sets it (compose's answeredByHelper)
|
ProviderModule: contract.Module, Contributed: contributed}}}})
|
||||||
}
|
|
||||||
ports := map[int]int{}
|
|
||||||
for _, l := range module.Listens { // compose's portsFor
|
|
||||||
where, mayAssign := module.MachineSide(l.Port)
|
|
||||||
if at, known := c.placed[l.Port]; mayAssign && known {
|
|
||||||
where = at
|
|
||||||
}
|
|
||||||
ports[l.Port] = where
|
|
||||||
}
|
|
||||||
composed, err := r.Compose(catalogue.Rendering{Hands: true, Provisioner: "mesh-provisioner-client",
|
|
||||||
ArtifactStore: "store:5000", Planned: true, Ports: map[string]map[int]int{c.module: ports}})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%s: %v", c.name, err)
|
|
||||||
}
|
|
||||||
value, err := provisions.EncodePlan(provisions.Plan{Node: c.node, Module: c.module, Plan: composed.Plans[c.module]})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s: %v", c.name, err)
|
t.Fatalf("%s: %v", c.name, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,9 @@
|
|||||||
// row 34; the operator, 2026-10-31: "the route-proxy should define its own contract for the seat (with the message
|
// row 34; the operator, 2026-10-31: "the route-proxy should define its own contract for the seat (with the message
|
||||||
// contracts of course) which other modules can use").
|
// contracts of course) which other modules can use").
|
||||||
//
|
//
|
||||||
// **Published by the repository that holds route-proxy, as its own Go module**, versioned by tags of the form
|
// **A package of the route-proxy module**, imported as `route-proxy/contract`: standard library only, built from the
|
||||||
// `modules/route-proxy/contract/vX.Y.Z`, the subdirectory form Go's module system expects, the same way mesh-sdk is
|
// same tree as the proxy, so the two never drift. No other module imports it today; when one must, it moves into the
|
||||||
// published (`go/vX.Y.Z`). A module that asks a route, reads what the proxy serves or hears its events imports this
|
// networking domain's package (research 081).
|
||||||
// package; nothing imports the repository. Standard library only, so a consumer takes nothing else with it.
|
|
||||||
//
|
//
|
||||||
// **How a route travels.** A module that must be reachable requires `route` and says, in its manifest's
|
// **How a route travels.** A module that must be reachable requires `route` and says, in its manifest's
|
||||||
// `contributes.route`, one Request, or several by local name; Schema is that object's JSON schema. The seat
|
// `contributes.route`, one Request, or several by local name; Schema is that object's JSON schema. The seat
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module route-proxy
|
|||||||
go 1.26.0
|
go 1.26.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261102112556-abf5eace7791
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261102191058-f02f142af128
|
||||||
github.com/nats-io/nats.go v1.54.0
|
github.com/nats-io/nats.go v1.54.0
|
||||||
golang.org/x/crypto v0.57.0
|
golang.org/x/crypto v0.57.0
|
||||||
)
|
)
|
||||||
@@ -16,5 +16,3 @@ require (
|
|||||||
golang.org/x/sys v0.48.0 // indirect
|
golang.org/x/sys v0.48.0 // indirect
|
||||||
golang.org/x/text v0.42.0 // indirect
|
golang.org/x/text v0.42.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
// The contract is this repository's own Go module, beside this one (contract/): built from the tree, not fetched.
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261102112556-abf5eace7791 h1:7SYIDPMxbPBr8dMB6k9fYsgVt4ZyWVL41q4LMFsfAvs=
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261102191058-f02f142af128 h1:aI1DhZAuqVBXbybSqhLNOGX5rUOrn9T0cHNCDUQF7IQ=
|
||||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261102112556-abf5eace7791/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261102191058-f02f142af128/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
|
||||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
|
||||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
|
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
|
||||||
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
|
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
|
||||||
|
|||||||
Reference in New Issue
Block a user