Add L0-L4 security clearance for fleet commands and AI elevation.
Gate manual and AI commands by per-agent clearance, auto-elevate stuck hosts to L4 when AI mode allows, and surface clearance in Access Depth and LOTL timeline.
This commit is contained in:
114
server/internal/clearance/levels.go
Normal file
114
server/internal/clearance/levels.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package clearance
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Security clearance levels (L0–L4).
|
||||
const (
|
||||
L0 = 0 // stats / read-only
|
||||
L1 = 1 // mining commands
|
||||
L2 = 2 // spread
|
||||
L3 = 3 // shell
|
||||
L4 = 4 // forge / version
|
||||
)
|
||||
|
||||
// LevelLabel returns the badge string for a clearance level.
|
||||
func LevelLabel(level int) string {
|
||||
if level < L0 {
|
||||
level = L0
|
||||
}
|
||||
if level > L4 {
|
||||
level = L4
|
||||
}
|
||||
return fmt.Sprintf("L%d", level)
|
||||
}
|
||||
|
||||
// LevelPermissions describes what each level allows (UI tooltips).
|
||||
func LevelPermissions(level int) string {
|
||||
switch level {
|
||||
case L0:
|
||||
return "stats and read-only probes"
|
||||
case L1:
|
||||
return "mining: pause, resume, restart"
|
||||
case L2:
|
||||
return "spread: discover_and_join, spread_now, stage_fetch"
|
||||
case L3:
|
||||
return "shell: exec_shell, agent_command"
|
||||
case L4:
|
||||
return "forge: set_agent_version, reorder_tiers fleet-wide"
|
||||
default:
|
||||
return "unknown clearance"
|
||||
}
|
||||
}
|
||||
|
||||
// ActionRequiredLevel maps a remote agent action to the minimum clearance level.
|
||||
func ActionRequiredLevel(action string) int {
|
||||
switch normalizeKey(action) {
|
||||
case "pause", "resume", "restart", "restart_mining", "start_mining", "stop":
|
||||
return L1
|
||||
case "discover_and_join", "spread_now", "stage_fetch":
|
||||
return L2
|
||||
case "exec", "exec_shell", "powershell", "agent_command":
|
||||
return L3
|
||||
case "fetch_module", "set_agent_version", "reorder_tiers", "adaptive_strategy_update":
|
||||
return L4
|
||||
default:
|
||||
return L0
|
||||
}
|
||||
}
|
||||
|
||||
// CommandRequiredLevel maps a fleet AI command type to the minimum clearance level.
|
||||
func CommandRequiredLevel(cmdType string, args map[string]interface{}) int {
|
||||
typ := normalizeKey(cmdType)
|
||||
switch typ {
|
||||
case "noop", "":
|
||||
return L0
|
||||
case "restart_mining":
|
||||
return L1
|
||||
case "discover_and_join", "spread_now", "stage_fetch":
|
||||
return L2
|
||||
case "agent_command":
|
||||
if args != nil {
|
||||
if action, ok := args["action"].(string); ok && action != "" {
|
||||
return ActionRequiredLevel(action)
|
||||
}
|
||||
}
|
||||
return L3
|
||||
case "bulk_command":
|
||||
if args != nil {
|
||||
if action, ok := args["action"].(string); ok && action != "" {
|
||||
return ActionRequiredLevel(action)
|
||||
}
|
||||
}
|
||||
return L1
|
||||
case "set_agent_version", "reorder_tiers":
|
||||
return L4
|
||||
default:
|
||||
return ActionRequiredLevel(typ)
|
||||
}
|
||||
}
|
||||
|
||||
// EnforceClearance returns an error when agentClearance is below the command requirement.
|
||||
func EnforceClearance(cmdType string, args map[string]interface{}, agentClearance int) error {
|
||||
required := CommandRequiredLevel(cmdType, args)
|
||||
if agentClearance >= required {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("clearance %s insufficient for %s (requires %s)", LevelLabel(agentClearance), cmdType, LevelLabel(required))
|
||||
}
|
||||
|
||||
// EnforceAction is the manual API path for raw agent actions.
|
||||
func EnforceAction(action string, agentClearance int) error {
|
||||
required := ActionRequiredLevel(action)
|
||||
if agentClearance >= required {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("clearance %s insufficient for %s (requires %s)", LevelLabel(agentClearance), action, LevelLabel(required))
|
||||
}
|
||||
|
||||
func normalizeKey(s string) string {
|
||||
s = strings.TrimSpace(strings.ToLower(s))
|
||||
return strings.ReplaceAll(s, "-", "_")
|
||||
}
|
||||
Reference in New Issue
Block a user