hub v0.62.0 + scripts v1.19.0 — R-21 slice C: the universal secret-free ISO
A generic ISO carries NO customer secret. The box registers itself at the hub as an unclaimed appliance; the operator binds it to a customer; the hub delivers the customer-id + retrieval passphrase ONCE; day-0 completes via the slice-A path. Hub (v0.62.0): - store/appliance.go: appliance_registrations keyed by (uuid, mac_set) — MAC set is the tiebreaker (duplicate SMBIOS UUIDs); token stored as sha256 only. Idempotent register (sticky-discard), atomic one-shot delivery, bind/discard. - api/appliance.go: POST /appliance/register (the one unauth endpoint, per-IP rate-limited, 256-bit token); GET /appliance/poll (404 no-oracle / 204 unbound / 200 deliver-once / 410 delivered). Passphrase read live, never logged. - web/appliances.go: Hosts-page "Unclaimed appliances" section + BIND (customer picker, host count display-only) + DISCARD; SSH host-key fingerprints; events. - Red-proofs: one-shot delivery + register idempotency (both proven red); 404-no-oracle, sticky-discard, bind staging, render. Green + confirm gate. Scripts (v1.19.0): - felhom-bootstrap.sh: ONE unit, TWO modes. Direct (env has customer/passphrase) = slice-A path, byte-identical, only branched around. Pairing (generic) = register + poll (RestartSec=30 is the poll timer); on delivery write the env 0600 and fall through to direct. Secrets + token shredded on success. - build-felhom-iso.sh --pairing: generic secret-free ISO, -generic filename, manifest mode=pairing. profiles/generic.profile (new). - test/bootstrap-modes.sh: Scenario D (direct = zero appliance calls) + pairing register/poll + delivery handoff — all green in a debian container.
This commit is contained in:
@@ -334,8 +334,19 @@ func (s *Server) handleHostsList(w http.ResponseWriter, r *http.Request) {
|
||||
rows = append(rows, row)
|
||||
}
|
||||
|
||||
// R-21 slice C: the unclaimed-appliance section + bind picker.
|
||||
unclaimed, picker, err := s.gatherUnclaimed(time.Now())
|
||||
if err != nil {
|
||||
s.logger.Printf("[ERROR] Hosts list: unclaimed appliances: %v", err)
|
||||
// non-fatal: still render the host list
|
||||
}
|
||||
|
||||
data := map[string]interface{}{
|
||||
"Hosts": rows,
|
||||
"Hosts": rows,
|
||||
"Unclaimed": unclaimed,
|
||||
"CustomerPicker": picker,
|
||||
"Flash": r.URL.Query().Get("flash"),
|
||||
"CSRFToken": s.getCSRFToken(r),
|
||||
}
|
||||
if err := s.templates.ExecuteTemplate(w, "hosts.html", data); err != nil {
|
||||
s.logger.Printf("[ERROR] hosts.html template: %v", err)
|
||||
|
||||
Reference in New Issue
Block a user