package track4 import ( "bytes" "context" "encoding/json" "os" "path/filepath" "testing" "net/http" "net/http/httptest" "github.com/stretchr/testify/require" ) type stubRoleManager struct { allowed bool gotIP string logs int } func (s *stubRoleManager) IsIPWhitelisted(_ context.Context, _ string, ipAddress string) (bool, error) { s.gotIP = ipAddress return s.allowed, nil } func (s *stubRoleManager) LogOperatorEvent(_ context.Context, _ string, _ *int, _ string, _ string, _ string, _ map[string]interface{}, _ string, _ string) error { s.logs++ return nil } func TestHandleRunScriptUsesForwardedClientIPAndRunsAllowlistedScript(t *testing.T) { root := t.TempDir() scriptPath := filepath.Join(root, "echo.sh") require.NoError(t, os.WriteFile(scriptPath, []byte("#!/usr/bin/env bash\necho hello \"$1\"\n"), 0o644)) t.Setenv("OPERATOR_SCRIPTS_ROOT", root) t.Setenv("OPERATOR_SCRIPT_ALLOWLIST", "echo.sh") t.Setenv("OPERATOR_SCRIPT_TIMEOUT_SEC", "30") t.Setenv("TRUST_PROXY_CIDRS", "10.0.0.0/8") roleMgr := &stubRoleManager{allowed: true} s := &Server{roleMgr: roleMgr, chainID: 138} reqBody := []byte(`{"script":"echo.sh","args":["world"]}`) req := httptest.NewRequest(http.MethodPost, "/api/v1/track4/operator/run-script", bytes.NewReader(reqBody)) req = req.WithContext(context.WithValue(req.Context(), "user_address", "0x4A666F96fC8764181194447A7dFdb7d471b301C8")) req.RemoteAddr = "10.0.0.10:8080" req.Header.Set("X-Forwarded-For", "203.0.113.9, 10.0.0.10") w := httptest.NewRecorder() s.HandleRunScript(w, req) require.Equal(t, http.StatusOK, w.Code) require.Equal(t, "203.0.113.9", roleMgr.gotIP) require.Equal(t, 2, roleMgr.logs) var out struct { Data map[string]any `json:"data"` } require.NoError(t, json.Unmarshal(w.Body.Bytes(), &out)) require.Equal(t, "echo.sh", out.Data["script"]) require.Equal(t, float64(0), out.Data["exit_code"]) require.Equal(t, "hello world", out.Data["stdout"]) require.Equal(t, false, out.Data["timed_out"]) } func TestHandleRunScriptRejectsNonAllowlistedScript(t *testing.T) { root := t.TempDir() require.NoError(t, os.WriteFile(filepath.Join(root, "allowed.sh"), []byte("#!/usr/bin/env bash\necho ok\n"), 0o644)) require.NoError(t, os.WriteFile(filepath.Join(root, "blocked.sh"), []byte("#!/usr/bin/env bash\necho blocked\n"), 0o644)) t.Setenv("OPERATOR_SCRIPTS_ROOT", root) t.Setenv("OPERATOR_SCRIPT_ALLOWLIST", "allowed.sh") s := &Server{roleMgr: &stubRoleManager{allowed: true}, chainID: 138} req := httptest.NewRequest(http.MethodPost, "/api/v1/track4/operator/run-script", bytes.NewReader([]byte(`{"script":"blocked.sh"}`))) req = req.WithContext(context.WithValue(req.Context(), "user_address", "0x4A666F96fC8764181194447A7dFdb7d471b301C8")) req.RemoteAddr = "127.0.0.1:9999" w := httptest.NewRecorder() s.HandleRunScript(w, req) require.Equal(t, http.StatusForbidden, w.Code) require.Contains(t, w.Body.String(), "script not in OPERATOR_SCRIPT_ALLOWLIST") }