package host import ( "context" "crypto/ed25519" "crypto/sha256" "debug/buildinfo" "encoding/hex" "io" "os" "time" "github.com/carlosframework/platform/internal/registry" "github.com/carlosframework/platform/internal/release" "github.com/carlosframework/platform/internal/rootstate" ) func openRootHistory(store release.Store, optDir string) (*release.RootHistoryPass, error) { s, err := rootstate.Open(release.RootHistoryDir, true, false) if err != nil { return nil, err } source := productionProofBindingSource(store, systemdUnits{}, optDir) h := boundRootHistory(&release.RootHistory{Store: s}, source.resolve, productionProofObserver(optDir)) h.Creation = rootHistoryCreation(store) m := rootHistoryMaintenance{history: h.History, store: store, source: source, checks: productionRootRestartChecks(systemdUnits{}, optDir), now: time.Now, readback: func(ctx context.Context, b release.HistoryBinding, snapshot func(context.Context) (release.HistoryMigrationStatus, error)) error { return publishRootHistoryReadback(ctx, store, b, snapshot) }, pub: func() (ed25519.PublicKey, error) { return release.ParsePublicKey(os.Getenv("CARLOS_RELEASE_PUBKEY"), "CARLOS_RELEASE_PUBKEY") }, projection: func() (rootstate.Store, error) { return rootstate.Open(release.RootHistoryStatusDir, true, true) }, } h.Reconstruct = m.run return h, nil } func boundRootHistory(h *release.RootHistory, resolve proofBindingResolver, obs proofObserver) *release.RootHistoryPass { return &release.RootHistoryPass{History: h, Resolve: func(ctx context.Context, rt registry.Route) (release.HistoryBinding, string, error) { if resolve == nil { return release.HistoryBinding{}, "", os.ErrPermission } b, err := resolve(ctx, rt) if err != nil { return release.HistoryBinding{}, "", err } if rt.Channel != b.Route.Channel { return release.HistoryBinding{}, "", os.ErrPermission } return release.HistoryBinding{Host: b.Route.Host, Account: b.Route.Account, App: b.Route.App}, b.Source, nil }, Installed: func(ctx context.Context, rt registry.Route, version string) (string, error) { if err := ctx.Err(); err != nil { return "", err } b, err := obs.observe(rt, 0) if err != nil { return "", err } if b.Version != version || b.binding.Version != version || b.binding.Digest != b.SHA256 || obs.procExe == nil { return "", os.ErrPermission } f, err := os.Open(obs.procExe(b.pid)) if err != nil { return "", err } defer f.Close() digest := sha256.New() if _, err := io.Copy(digest, f); err != nil { return "", err } if hex.EncodeToString(digest.Sum(nil)) != b.SHA256 { return "", os.ErrPermission } program := "" if info, err := buildinfo.Read(f); err == nil { program = info.Path } again, err := obs.observe(rt, 0) if err != nil || again.SHA256 != b.SHA256 || again.Version != b.Version || again.binding.Source != b.binding.Source || again.pid != b.pid || again.start != b.start || again.invocation != b.invocation { return "", os.ErrPermission } return program, nil }, } } func recordRootProgram(h *release.RootHistoryPass, b liveBuild) error { ctx := context.Background() binding, source, err := h.Resolve(ctx, b.binding.Route) if err != nil { return err } if source != b.binding.Source { return os.ErrPermission } program, err := h.Installed(ctx, b.binding.Route, b.Version) if err != nil { return err } again, revision, err := h.Resolve(ctx, b.binding.Route) if err != nil || again != binding || revision != source { return os.ErrPermission } return h.History.RecordInstalledProgram(binding, program) }