v0.19.0: bootstrap contract v2 — relay hub retrieval passphrase (no host key in guest)

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>
This commit is contained in:
2026-06-11 13:22:51 +02:00
parent e4dfe5ccc7
commit e5a18194f4
7 changed files with 88 additions and 48 deletions
+8 -7
View File
@@ -11,9 +11,9 @@ import (
// bootstrap_test.go ingests the same shape. A drift here (or there) breaks provisioning.
func TestDoc_ContractKeySet(t *testing.T) {
d := Doc{
Schema: SchemaV1,
Customer: DocCustomer{ID: "c", Name: "n", Domain: "d", Email: "e"},
Hub: DocHub{URL: "u", APIKey: "k", HostID: "h"},
Schema: SchemaV2,
Customer: DocCustomer{ID: "c"},
Hub: DocHub{URL: "u", RetrievalPassword: "p"},
LocalAPI: DocLocalAPI{Endpoint: "ep", Fingerprint: "fp", Token: "tok"},
}
b, err := d.render()
@@ -34,12 +34,13 @@ func TestDoc_ContractKeySet(t *testing.T) {
if err := json.Unmarshal(b, &full); err != nil {
t.Fatal(err)
}
assertKeys(t, "customer", full.Customer, []string{"id", "name", "domain", "email"})
assertKeys(t, "hub", full.Hub, []string{"url", "api_key", "host_id"})
// 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 SchemaV1 != "felhom.bootstrap/v1" {
t.Fatalf("schema drift: %q", SchemaV1)
if SchemaV2 != "felhom.bootstrap/v2" {
t.Fatalf("schema drift: %q", SchemaV2)
}
}