projection: begin the exact-path public epoch

The public tree and its history contain only the listed paths. Earlier projection history remains preserved internally.

Source-Sha: 913fde029b935671833254797f0f20f1eb9fabba

Policy-Sha: 913fde029b935671833254797f0f20f1eb9fabba

Tree-Digest: 180ae530c1058a2a5c89837bdce2d323ae83e669e38590ca72e75b8d92b7262f
This commit is contained in:
Fimeg 2026-09-08 21:59:33 -04:00
commit 67e26be2d9
838 changed files with 157302 additions and 0 deletions

View file

@ -0,0 +1,240 @@
// Package desktop manages the native Qt/QML local-machine operations console.
// The agent service spawns the desktop binary as a child process when a desktop
// session is available. The binary connects back to the agent's local API socket
// and presents Agent-owned machine state and bounded operator intent.
package desktop
import (
"context"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"sync"
"time"
)
// Manager handles spawning and monitoring the desktop app process.
type Manager struct {
binPath string
enabled bool
maxRestarts int
restartDelay time.Duration
mu sync.Mutex
cmd *exec.Cmd
cancel context.CancelFunc
stopped bool
lastHealth healthReport
}
// healthReport is Desktop's most recent POST /v1/desktop self-report. On
// Linux Desktop is launched by XDG autostart, not by this manager, so the
// spawned-process state is always empty there — the health report is the only
// liveness and version signal the agent has.
type healthReport struct {
version string
windowOpen bool
reportedAt time.Time
}
// healthFreshness is how long a health report counts as proof of a live Desktop.
// Desktop reports every 30s; three missed beats means it is gone.
const healthFreshness = 90 * time.Second
// HealthSnapshot is the fleet-reportable desktop component state.
type HealthSnapshot struct {
Installed bool `json:"installed"`
Running bool `json:"running"`
Version string `json:"version,omitempty"`
WindowOpen bool `json:"window_open,omitempty"`
LastReport string `json:"last_report,omitempty"`
}
// NewManager creates a desktop manager. binPath is the path to the redflag-desktop
// binary (empty string = auto-detect alongside the agent binary).
func NewManager(binPath string, enabled bool, maxRestarts, restartDelaySec int) *Manager {
if binPath == "" {
binPath = autoDetectBinary()
}
if restartDelaySec <= 0 {
restartDelaySec = 5
}
return &Manager{
binPath: binPath,
enabled: enabled,
maxRestarts: maxRestarts,
restartDelay: time.Duration(restartDelaySec) * time.Second,
}
}
// autoDetectBinary finds the desktop binary alongside the agent binary.
func autoDetectBinary() string {
execPath, err := os.Executable()
if err != nil {
return ""
}
dir := filepath.Dir(execPath)
name := "redflag-desktop"
if runtime.GOOS == "windows" {
name = "redflag-desktop.exe"
}
return filepath.Join(dir, name)
}
// IsAvailable checks if the desktop binary exists and a desktop session is detectable.
func (m *Manager) IsAvailable() bool {
if m.binPath == "" {
return false
}
info, err := os.Stat(m.binPath)
if err != nil || info.IsDir() {
return false
}
return hasDesktopSession()
}
// Start begins managing the desktop process. It blocks until Stop() is called
// or the context is cancelled. Spawns the binary, restarts on crash up to
// maxRestarts times.
func (m *Manager) Start(ctx context.Context) {
if !m.enabled {
log.Printf("[INFO] [agent] [desktop] disabled by config")
return
}
if !m.IsAvailable() {
log.Printf("[INFO] [agent] [desktop] not available — binary=%s session_detected=false", m.binPath)
return
}
log.Printf("[INFO] [agent] [desktop] starting binary=%s", m.binPath)
m.mu.Lock()
ctx, m.cancel = context.WithCancel(ctx)
m.stopped = false
m.mu.Unlock()
restarts := 0
for {
select {
case <-ctx.Done():
log.Printf("[INFO] [agent] [desktop] stopped (context cancelled)")
return
default:
}
if m.maxRestarts > 0 && restarts >= m.maxRestarts {
log.Printf("[WARNING] [agent] [desktop] max restarts reached (%d), giving up", m.maxRestarts)
return
}
err := m.run(ctx)
if err == nil {
// Clean exit — don't restart.
log.Printf("[INFO] [agent] [desktop] exited cleanly")
return
}
restarts++
log.Printf("[WARNING] [agent] [desktop] process exited with error: %v (restart %d)", err, restarts)
select {
case <-ctx.Done():
return
case <-time.After(m.restartDelay):
}
}
}
// run spawns the desktop binary and waits for it to exit.
func (m *Manager) run(ctx context.Context) error {
m.mu.Lock()
cmd := exec.CommandContext(ctx, m.binPath)
m.cmd = cmd
m.mu.Unlock()
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Start(); err != nil {
return fmt.Errorf("start desktop: %w", err)
}
log.Printf("[INFO] [agent] [desktop] spawned pid=%d", cmd.Process.Pid)
return cmd.Wait()
}
// Stop terminates the desktop process if running.
func (m *Manager) Stop() {
m.mu.Lock()
defer m.mu.Unlock()
if m.cancel != nil {
m.cancel()
}
m.stopped = true
if m.cmd != nil && m.cmd.Process != nil {
log.Printf("[INFO] [agent] [desktop] terminating pid=%d", m.cmd.Process.Pid)
m.cmd.Process.Kill()
}
}
// Status returns current desktop process state.
func (m *Manager) Status() (running bool, pid int) {
m.mu.Lock()
defer m.mu.Unlock()
if m.cmd == nil || m.cmd.Process == nil {
return false, 0
}
// Check if process is still alive.
if m.cmd.ProcessState != nil && m.cmd.ProcessState.Exited() {
return false, 0
}
return true, m.cmd.Process.Pid
}
// RecordHealth stores Desktop's self-report (POST /v1/desktop via localapi).
func (m *Manager) RecordHealth(version string, windowOpen bool) {
m.mu.Lock()
defer m.mu.Unlock()
m.lastHealth = healthReport{
version: version,
windowOpen: windowOpen,
reportedAt: time.Now().UTC(),
}
}
// Health returns the desktop component state for fleet reporting. Running is
// true when this manager spawned a live process (Windows) or when a health
// report landed within the freshness window (Linux autostart path).
func (m *Manager) Health() HealthSnapshot {
running, _ := m.Status()
m.mu.Lock()
last := m.lastHealth
m.mu.Unlock()
snap := HealthSnapshot{Running: running}
if m.binPath != "" {
if info, err := os.Stat(m.binPath); err == nil && !info.IsDir() {
snap.Installed = true
}
}
if !last.reportedAt.IsZero() {
snap.Version = last.version
snap.WindowOpen = last.windowOpen
snap.LastReport = last.reportedAt.Format(time.RFC3339)
if time.Since(last.reportedAt) <= healthFreshness {
snap.Running = true
}
}
return snap
}

View file

@ -0,0 +1,55 @@
package desktop
import (
"os"
"strings"
)
// hasDesktopSession checks if a desktop session is available on Linux.
// Looks for DISPLAY or WAYLAND_DISPLAY in the environment, which indicates
// an X11 or Wayland session is active.
func hasDesktopSession() bool {
// Check standard environment variables.
if os.Getenv("DISPLAY") != "" || os.Getenv("WAYLAND_DISPLAY") != "" {
return true
}
// Fallback: scan /proc for a running desktop session (the agent service
// may not inherit DISPLAY from systemd).
return findDesktopSessionInProc()
}
// findDesktopSessionInProc scans /proc/*/environ for DISPLAY or WAYLAND_DISPLAY.
// Returns true if any user process has a desktop session active.
func findDesktopSessionInProc() bool {
entries, err := os.ReadDir("/proc")
if err != nil {
return false
}
for _, entry := range entries {
if !entry.IsDir() {
continue
}
// Only check numeric (PID) directories.
if entry.Name()[0] < '0' || entry.Name()[0] > '9' {
continue
}
data, err := os.ReadFile("/proc/" + entry.Name() + "/environ")
if err != nil {
continue
}
for _, v := range strings.Split(string(data), "\x00") {
if strings.HasPrefix(v, "DISPLAY=") && len(v) > 8 {
return true
}
if strings.HasPrefix(v, "WAYLAND_DISPLAY=") && len(v) > 17 {
return true
}
}
}
return false
}

View file

@ -0,0 +1,11 @@
//go:build !linux && !windows
package desktop
import "os"
// hasDesktopSession checks if a desktop session is available on other platforms.
// Default: check for DISPLAY environment variable.
func hasDesktopSession() bool {
return os.Getenv("DISPLAY") != ""
}

View file

@ -0,0 +1,27 @@
package desktop
import (
"os/exec"
"strings"
)
// hasDesktopSession checks if a desktop session is available on Windows.
// Looks for an active console session via query session.
func hasDesktopSession() bool {
// query session lists all sessions. An active console session with
// a logged-in user means a desktop is available.
out, err := exec.Command("query", "session").Output()
if err != nil {
return false
}
lines := strings.Split(string(out), "\n")
for _, line := range lines {
// Active console sessions have "Active" in the state column.
if strings.Contains(line, "Active") && strings.Contains(line, "console") {
return true
}
}
return false
}