feat: add config apply endpoint and config hash in reports

- POST /api/config/apply: accepts YAML body from Hub, validates and
  writes controller.yaml atomically (tmp+rename)
- GET /api/config/hash: returns SHA256 hash of current config file
- Report payload now includes config_hash field for Hub comparison
- Config endpoints use same dual auth as self-update (session OR Bearer)
- config.LoadFromBytes() for validation without file I/O
- config.FileHash() helper for SHA256 computation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-20 16:13:35 +01:00
parent dc5209288b
commit 85d1f2f673
5 changed files with 109 additions and 7 deletions
+12
View File
@@ -1,7 +1,10 @@
package report
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"os"
"strconv"
"strings"
"time"
@@ -19,6 +22,7 @@ import (
// BuildReport collects current state from all subsystems and returns a Report.
func BuildReport(
cfg *config.Config,
configPath string,
stackMgr *stacks.Manager,
backupMgr *backup.Manager,
cpuCollector *system.CPUCollector,
@@ -39,6 +43,14 @@ func BuildReport(
r.ControllerURL = fmt.Sprintf("https://felhom.%s", cfg.Customer.Domain)
}
// Config hash for Hub comparison
if configPath != "" {
if data, err := os.ReadFile(configPath); err == nil {
h := sha256.Sum256(data)
r.ConfigHash = hex.EncodeToString(h[:])
}
}
// System info
staticInfo := metrics.GetStaticInfo()
hddPath := cfg.Paths.HDDPath
+1
View File
@@ -9,6 +9,7 @@ type Report struct {
CustomerName string `json:"customer_name"`
ControllerVersion string `json:"controller_version"`
ControllerURL string `json:"controller_url,omitempty"`
ConfigHash string `json:"config_hash,omitempty"`
Timestamp time.Time `json:"timestamp"`
ReportingDisabled bool `json:"reporting_disabled,omitempty"`
System SystemReport `json:"system"`