v0.334.0: a live box refreshes its config with its own hub key (GET /box-config; R-1159, operator D19)
gates / gates (push) Successful in 49s

This commit is contained in:
2026-10-19 15:55:10 +02:00
parent e1a2abf1e3
commit 546eef37bd
5 changed files with 205 additions and 1 deletions
+54
View File
@@ -59,3 +59,57 @@ func PullConfig(hubURL, customerID, retrievalPassword string) (string, error) {
return string(body), nil
}
// ErrBoxConfigUnsupported: the hub has no GET /box-config (a hub before v0.161.0) — the caller falls back to the
// passphrase pull.
var ErrBoxConfigUnsupported = errors.New("hub has no box-config route")
// PullBoxConfig fetches the generated controller.yaml with the box's OWN hub key (GET /api/v1/box-config/{id}, hub ≥
// v0.161.0; R-1159). A live box refreshes its config this way, so the hub can refuse the household's retrieval
// passphrase once the box is live (hub `api/passphrase_scope.go`).
func PullBoxConfig(hubURL, customerID, apiKey string) (string, error) {
url := strings.TrimRight(hubURL, "/") + "/api/v1/box-config/" + customerID
client := &http.Client{Timeout: 30 * time.Second}
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return "", fmt.Errorf("%w: %v", ErrHubError, err)
}
req.Header.Set("Authorization", "Bearer "+apiKey)
resp, err := client.Do(req)
if err != nil {
return "", fmt.Errorf("%w: %v", ErrHubUnreachable, err)
}
defer resp.Body.Close()
switch resp.StatusCode {
case http.StatusOK:
case http.StatusUnauthorized:
return "", ErrAuthFailed
case http.StatusNotFound, http.StatusMethodNotAllowed:
return "", ErrBoxConfigUnsupported
default:
return "", fmt.Errorf("%w: HTTP %d", ErrHubError, resp.StatusCode)
}
body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
if err != nil {
return "", fmt.Errorf("%w: reading response: %v", ErrHubError, err)
}
return string(body), nil
}
// PullConfigPreferKey is the LIVE box's config refresh (report.ConfigRefresher): with the box's own key first; the
// retrieval passphrase only when the hub has no box-config route (a hub before v0.161.0) or the box holds no key yet.
// Any other answer to the key pull is returned as it is — never retried with the passphrase (R-1159: the passphrase
// is for a box that has no key of its own). Pinned by TestR1159_RefreshUsesTheBoxKey.
func PullConfigPreferKey(hubURL, customerID, apiKey, retrievalPassword string, logf func(string, ...any)) (string, error) {
if apiKey != "" {
y, err := PullBoxConfig(hubURL, customerID, apiKey)
if !errors.Is(err, ErrBoxConfigUnsupported) {
if err == nil {
logf("[INFO] [config] refreshed controller.yaml with the box's own hub key (box-config)")
}
return y, err
}
logf("[INFO] [config] the hub has no box-config route (hub < 0.161.0) — refreshing with the retrieval passphrase")
}
return PullConfig(hubURL, customerID, retrievalPassword)
}