e5a18194f4
Lockstep with felhom-controller v0.40.0. The agent now bakes a v2 bootstrap.json
carrying only what the controller needs to PULL its config from the hub:
customer.id + hub.url + hub.retrieval_password + the per-guest local_api. Stops
baking the agent's host hub key/host_id (and customer name/domain/email) into the
guest — the controller gets the customer-scoped key from the hub pull.
- internal/provision/doc.go: SchemaV2; DocCustomer{id}; DocHub{url,retrieval_password}.
- backhalf.go: render v2; require customer.id + hub.url + hub.retrieval_password.
- cmd/.../main.go --selftest=provision: new required -hub-password flag; stop
baking APIKey/HostID; -customer-domain/name/email accepted but not baked.
- configs/build-golden.sh: default CONTROLLER_IMAGE off stale :v0.35.0 -> :0.40.0.
- doc_test.go/backhalf_test.go updated to v2 shape.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
64 lines
1.8 KiB
Go
64 lines
1.8 KiB
Go
package provision
|
|
|
|
import (
|
|
"encoding/json"
|
|
"sort"
|
|
"testing"
|
|
)
|
|
|
|
// The bootstrap.json key set is a CROSS-REPO contract: it must match felhom-controller's
|
|
// internal/bootstrap.Bootstrap exactly. This test pins the emitted key set; the controller's
|
|
// bootstrap_test.go ingests the same shape. A drift here (or there) breaks provisioning.
|
|
func TestDoc_ContractKeySet(t *testing.T) {
|
|
d := Doc{
|
|
Schema: SchemaV2,
|
|
Customer: DocCustomer{ID: "c"},
|
|
Hub: DocHub{URL: "u", RetrievalPassword: "p"},
|
|
LocalAPI: DocLocalAPI{Endpoint: "ep", Fingerprint: "fp", Token: "tok"},
|
|
}
|
|
b, err := d.render()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var m map[string]json.RawMessage
|
|
if err := json.Unmarshal(b, &m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assertKeys(t, "top", m, []string{"schema", "customer", "hub", "local_api"})
|
|
|
|
var full struct {
|
|
Customer map[string]json.RawMessage `json:"customer"`
|
|
Hub map[string]json.RawMessage `json:"hub"`
|
|
LocalAPI map[string]json.RawMessage `json:"local_api"`
|
|
}
|
|
if err := json.Unmarshal(b, &full); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// v2: customer carries only id; hub carries url + retrieval_password (NO api_key/host_id).
|
|
assertKeys(t, "customer", full.Customer, []string{"id"})
|
|
assertKeys(t, "hub", full.Hub, []string{"url", "retrieval_password"})
|
|
assertKeys(t, "local_api", full.LocalAPI, []string{"endpoint", "fingerprint", "token"})
|
|
|
|
if SchemaV2 != "felhom.bootstrap/v2" {
|
|
t.Fatalf("schema drift: %q", SchemaV2)
|
|
}
|
|
}
|
|
|
|
func assertKeys(t *testing.T, label string, m map[string]json.RawMessage, want []string) {
|
|
t.Helper()
|
|
got := make([]string, 0, len(m))
|
|
for k := range m {
|
|
got = append(got, k)
|
|
}
|
|
sort.Strings(got)
|
|
sort.Strings(want)
|
|
if len(got) != len(want) {
|
|
t.Fatalf("%s: key set %v, want %v", label, got, want)
|
|
}
|
|
for i := range want {
|
|
if got[i] != want[i] {
|
|
t.Fatalf("%s: key set %v, want %v", label, got, want)
|
|
}
|
|
}
|
|
}
|