package hostfloor import ( "encoding/json" "github.com/carlosframework/platform/internal/release" "os" "path/filepath" "strings" ) type Running struct { ReleaseTag string Hash string Protocol int BootID string FloorSHA256 string GuardReady bool } func (d Disk) Running(build, platform string, role ...string) (Running, error) { component := "router" if len(role) == 1 { component = role[0] } else if len(role) > 1 { return Running{}, ErrFloor } _, f, err := d.Load() if err != nil { return Running{}, err } if component == "console" { path, err := os.ReadFile(filepath.Join(d.Dir, "console-ready.json")) if err != nil { return Running{}, err } dropin, err := os.ReadFile("/etc/systemd/system/console.service.d/90-host-floor.conf") if err != nil { return Running{}, err } want := ConsoleGuardDropIn(string(path)) if string(dropin) != want { return Running{}, ErrFloor } } hash, err := ExecutingHash() if err != nil { return Running{}, err } boot, err := os.ReadFile("/proc/sys/kernel/random/boot_id") if err != nil { return Running{}, err } entries, err := os.ReadDir(filepath.Join(d.Dir, "identities")) if err != nil { return Running{}, err } for _, entry := range entries { if entry.IsDir() { continue } raw, err := os.ReadFile(filepath.Join(d.Dir, "identities", entry.Name())) if err != nil { return Running{}, err } if CheckComponent(d.PublicKey, f, raw, build, platform, hash, component) != nil { continue } tag := strings.TrimSuffix(entry.Name(), ".json") if _, err := os.Stat(filepath.Join(d.Dir, "carlos")); err != nil { return Running{}, err } identity, err := release.VerifySystemIdentity(d.PublicKey, raw) if err != nil { return Running{}, err } return Running{tag, hash, identity.Current.MovesProtocol, strings.TrimSpace(string(boot)), f.Digest, true}, nil } return Running{}, ErrFloor } // Enrollment is installed by root from the verified roster. It is reporting // configuration; readers always compare it to the fresh signed roster. type Enrollment struct { Box string `json:"box"` Enrollment string `json:"enrollment"` InstanceID string `json:"instance_id"` } func ReadEnrollment(path string) (Enrollment, error) { raw, err := os.ReadFile(path) if err != nil { return Enrollment{}, err } var e Enrollment if json.Unmarshal(raw, &e) != nil || e.Box == "" || e.Enrollment == "" || e.InstanceID == "" { return Enrollment{}, ErrFloor } return e, nil } func ConsoleGuardDropIn(path string) string { return "[Service]\nExecStart=\nExecStart=/opt/carlos/system/guard/carlos system guard-exec console " + path + " serve\n" }