slice 8A (agent half): local-API server + provisioning back-half (v0.10.0)
internal/localapi: per-guest local-API server (doc 03 §6) — 7 self-scoped endpoints, hashed per-guest token store, persisted self-signed leaf with stable SHA-256 pin, optional 6th daemon goroutine. internal/provision: back-half — mint token, render bootstrap.json (no registry cred), write 0600, chown 100000:100000, attach pct-set bind mount (host-side, F3, no pct exec). --selftest=provision. build-golden.sh bakes the controller image + bootstrap unit. sudoers FELHOM_PROVISION; firewall narrowing artifact. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
// Package provision implements the slice-8A provisioning BACK HALF: after the slice-7 bring-up
|
||||
// front half (restore → identity → size → start), the agent mints a per-guest local-API token,
|
||||
// renders the stable bootstrap.json contract, and populates a read-only config mount the golden's
|
||||
// baked controller-bootstrap unit consumes (F3: host-side only, no pct exec).
|
||||
//
|
||||
// The agent NEVER enters the guest and NEVER puts a registry credential in the guest (the
|
||||
// controller image is baked into the golden — configs/build-golden.sh). The only secret written
|
||||
// into the guest is the per-guest local-API token, in the 0600 bootstrap.json on the config mount.
|
||||
package provision
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// SchemaV1 is the stable agent→controller contract version. It MUST stay byte-compatible with the
|
||||
// controller's internal/bootstrap.SchemaV1 / Bootstrap shape (cross-repo contract; doc_test.go
|
||||
// pins the key set, mirroring the controller's bootstrap_test.go).
|
||||
const SchemaV1 = "felhom.bootstrap/v1"
|
||||
|
||||
// Doc is the bootstrap.json the agent emits. Field names + json tags MUST match the controller's
|
||||
// internal/bootstrap.Bootstrap exactly. It carries ONLY what the controller needs to come up
|
||||
// configured and reach the agent's local API — no registry credential (image is baked).
|
||||
type Doc struct {
|
||||
Schema string `json:"schema"`
|
||||
Customer DocCustomer `json:"customer"`
|
||||
Hub DocHub `json:"hub"`
|
||||
LocalAPI DocLocalAPI `json:"local_api"`
|
||||
}
|
||||
|
||||
type DocCustomer struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Domain string `json:"domain"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
type DocHub struct {
|
||||
URL string `json:"url"`
|
||||
APIKey string `json:"api_key"`
|
||||
HostID string `json:"host_id"`
|
||||
}
|
||||
|
||||
type DocLocalAPI struct {
|
||||
Endpoint string `json:"endpoint"` // host bridge IP:port
|
||||
Fingerprint string `json:"fingerprint"` // agent leaf-cert SHA-256 (hex) to pin
|
||||
Token string `json:"token"` // per-guest bearer; SECRET — written 0600 only
|
||||
}
|
||||
|
||||
// render marshals the doc as indented JSON (the bytes written into the config mount).
|
||||
func (d Doc) render() ([]byte, error) {
|
||||
return json.MarshalIndent(d, "", " ")
|
||||
}
|
||||
Reference in New Issue
Block a user