Files
AetherForge/server/internal/api/clearance.go
AetherForge d9f36f182c
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Add phenotype cloning, failure atlas, AI court session, and clearance L0-L4
2026-06-07 02:41:54 -07:00

147 lines
3.6 KiB
Go

package api
import (
"fmt"
"sync"
fleetai "crypto-miner-server/internal/ai"
"crypto-miner-server/internal/clearance"
"crypto-miner-server/internal/models"
)
const stuckHostFailedTierThreshold = 14
// ClearanceManager returns the hub's session clearance tracker.
func (h *WSHub) ClearanceManager() *ClearanceManager {
if h == nil {
return nil
}
return h.clearance
}
// ClearanceManager tracks per-agent session clearance and broadcasts changes.
type ClearanceManager struct {
hub *WSHub
mu sync.RWMutex
// agentClearance holds live session clearance keyed by agent ID.
agentClearance map[string]int
}
func NewClearanceManager(hub *WSHub) *ClearanceManager {
return &ClearanceManager{
hub: hub,
agentClearance: make(map[string]int),
}
}
// InitAgent sets baseline clearance when an agent connects.
func (m *ClearanceManager) InitAgent(agentID string, agent *models.Agent) int {
if m == nil {
return clearance.DefaultClearance(agent)
}
level := clearance.DefaultClearance(agent)
m.mu.Lock()
m.agentClearance[agentID] = level
m.mu.Unlock()
// Baseline clearance is included in auth_response; push only on elevation.
return level
}
// RemoveAgent drops session clearance state.
func (m *ClearanceManager) RemoveAgent(agentID string) {
if m == nil {
return
}
m.mu.Lock()
delete(m.agentClearance, agentID)
m.mu.Unlock()
}
// Level returns the current session clearance for an agent.
func (m *ClearanceManager) Level(agentID string) int {
if m == nil {
return clearance.L0
}
m.mu.RLock()
level, ok := m.agentClearance[agentID]
m.mu.RUnlock()
if ok {
return level
}
if m.hub != nil && m.hub.db != nil {
if agent, err := m.hub.db.GetAgent(agentID); err == nil && agent != nil {
return clearance.DefaultClearance(agent)
}
}
return clearance.L0
}
// RequestElevation raises clearance when needed and notifies dashboards.
func (m *ClearanceManager) RequestElevation(agentID string, toLevel int, reason, source string) (int, error) {
if m == nil {
return clearance.L0, nil
}
current := m.Level(agentID)
newLevel, err := clearance.RequestElevation(m.hub.db, agentID, current, toLevel, reason, source)
if err != nil {
return current, err
}
if newLevel <= current {
return current, nil
}
m.mu.Lock()
m.agentClearance[agentID] = newLevel
m.mu.Unlock()
m.pushToAgent(agentID, newLevel)
m.broadcastElevation(agentID, current, newLevel, reason, source)
return newLevel, nil
}
func (m *ClearanceManager) pushToAgent(agentID string, level int) {
if m == nil || m.hub == nil {
return
}
_ = m.hub.SendToAgent(agentID, Message{
Type: "clearance_update",
Payload: mustMarshal(map[string]interface{}{
"clearance_level": level,
}),
})
}
func (m *ClearanceManager) broadcastElevation(agentID string, fromLevel, toLevel int, reason, source string) {
if m == nil || m.hub == nil {
return
}
m.hub.broadcastDashboard(Message{
Type: "clearance_elevated",
Payload: mustMarshal(map[string]interface{}{
"agent_id": agentID,
"from_level": fromLevel,
"to_level": toLevel,
"reason": reason,
"source": source,
}),
})
}
// ClearanceGuardExecutor wraps FleetAIExecutor with clearance enforcement.
type ClearanceGuardExecutor struct {
Inner *FleetAIExecutor
Clearance *ClearanceManager
}
func (e *ClearanceGuardExecutor) Execute(agentID string, cmd fleetai.Command) (string, error) {
if e == nil || e.Inner == nil {
return "", fmt.Errorf("executor unavailable")
}
level := clearance.L0
if e.Clearance != nil {
level = e.Clearance.Level(agentID)
}
if err := clearance.EnforceClearance(cmd.Type, cmd.Args, level); err != nil {
return "", err
}
return e.Inner.Execute(agentID, cmd)
}