diff --git a/agent/agent.go b/agent/agent.go index cd3c895..c0c947c 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -89,12 +89,11 @@ const ( nixMeshDir = "/opt/tacticalmesh" nixAgentBin = nixAgentDir + "/tacticalagent" nixAgentBinDir = nixAgentDir + "/bin" + nixAgentEtcDir = nixAgentDir + "/etc" nixMeshAgentBin = nixMeshDir + "/meshagent" macPlistPath = "/Library/LaunchDaemons/tacticalagent.plist" macPlistName = "tacticalagent" defaultMacMeshSvcDir = "/usr/local/mesh_services" - nuVersion = "0.87.0" - denoVersion = "v1.38.2" ) var defaultWinTmpDir = filepath.Join(os.Getenv("PROGRAMDATA"), "TacticalRMM") diff --git a/agent/agent_unix.go b/agent/agent_unix.go index aebd808..5de2595 100644 --- a/agent/agent_unix.go +++ b/agent/agent_unix.go @@ -167,7 +167,7 @@ func NewAgentConfig() *rmm.AgentConfig { return ret } -func (a *Agent) RunScript(code string, shell string, args []string, timeout int, runasuser bool, envVars []string) (stdout, stderr string, exitcode int, e error) { +func (a *Agent) RunScript(code string, shell string, args []string, timeout int, runasuser bool, envVars []string, nushellEnableConfig bool, denoDefaultPermissions string) (stdout, stderr string, exitcode int, e error) { code = removeWinNewLines(code) content := []byte(code) @@ -197,12 +197,21 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int, opts.IsScript = true switch shell { case "nushell": + var nushellArgs []string + if nushellEnableConfig { + nushellArgs = []string{ + "--config", + path.Join(nixAgentEtcDir, "nushell", "config.nu"), + "--env-config", + path.Join(nixAgentEtcDir, "nushell", "env.nu"), + } + } else { + nushellArgs = []string{"--no-config-file"} + } opts.Shell = a.NuBin - opts.Args = append([]string{ - "--no-config-file", - f.Name(), - }, - args...) + opts.Args = nushellArgs + opts.Args = append(opts.Args, f.Name()) + opts.Args = append(opts.Args, args...) if !trmm.FileExists(a.NuBin) { a.Logger.Errorln("RunScript(): Executable does not exist. Install Nu and try again:", a.NuBin) err := errors.New("File Not Found: " + a.NuBin) @@ -225,6 +234,8 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int, // https://docs.deno.com/runtime/manual/basics/permissions#permissions-list // DENO_PERMISSIONS is not an official environment variable. // https://docs.deno.com/runtime/manual/basics/env_variables + // DENO_DEFAULT_PERMISSIONS is used if not found in the environment variables. + found := false for i, v := range envVars { if strings.HasPrefix(v, "DENO_PERMISSIONS=") { permissions := strings.Split(v, "=")[1] @@ -232,9 +243,13 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int, // Remove the DENO_PERMISSIONS variable from the environment variables slice. // It's possible more variables may exist with the same prefix. envVars = append(envVars[:i], envVars[i+1:]...) + found = true break } } + if !found && denoDefaultPermissions != "" { + opts.Args = append(opts.Args, strings.Split(denoDefaultPermissions, " ")...) + } // Can't append a variadic slice after a string arg. // https://pkg.go.dev/builtin#append @@ -536,11 +551,321 @@ func (a *Agent) GetWMIInfo() map[string]interface{} { return wmiInfo } -// windows only below TODO add into stub file +// InstallNushell will download nushell from GitHub and install (copy) it to nixAgentBinDir +func (a *Agent) InstallNushell(force bool) { + conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI()) + if !conf.InstallNushell { + return + } + + if trmm.FileExists(a.NuBin) { + if force { + a.Logger.Debugln(a.NuBin, "InstallNushell(): Forced install. Removing nu binary.") + err := os.Remove(a.NuBin) + if err != nil { + a.Logger.Errorln("InstallNushell(): Error removing nu binary:", err) + return + } + } else { + return + } + } + + if !trmm.FileExists(nixAgentBinDir) { + err := os.MkdirAll(nixAgentBinDir, 0755) + if err != nil { + a.Logger.Errorln("InstallNushell(): Error creating nixAgentBinDir:", err) + return + } + } + + if conf.NushellEnableConfig { + // Create 0-byte config files for Nushell + nushellPath := path.Join(nixAgentEtcDir, "nushell") + nushellConfig := path.Join(nushellPath, "config.nu") + nushellEnv := path.Join(nushellPath, "env.nu") + if !trmm.FileExists(nushellPath) { + err := os.MkdirAll(nushellPath, 0755) + if err != nil { + a.Logger.Errorln("InstallNushell(): Error creating nixAgentEtcDir/nushell:", err) + return + } + } + + if !trmm.FileExists(nushellConfig) { + _, err := os.Create(nushellConfig) + if err != nil { + a.Logger.Errorln("InstallNushell(): Error creating nushell config.nu:", err) + return + } + err = os.Chmod(nushellConfig, 0744) + if err != nil { + a.Logger.Errorln("InstallNushell(): Error changing permissions for nushell config.nu:", err) + return + } + } + if !trmm.FileExists(nushellEnv) { + _, err := os.Create(nushellEnv) + if err != nil { + a.Logger.Errorln("InstallNushell(): Error creating nushell env.nu:", err) + return + } + err = os.Chmod(nushellEnv, 0744) + if err != nil { + a.Logger.Errorln("InstallNushell(): Error changing permissions for nushell env.nu:", err) + return + } + } + } + + var ( + assetName string + url string + targzDirName string + ) + + if conf.InstallNushellUrl != "" { + url = conf.InstallNushellUrl + url = strings.Replace(url, "{OS}", runtime.GOOS, -1) + url = strings.Replace(url, "{ARCH}", runtime.GOARCH, -1) + url = strings.Replace(url, "{VERSION}", conf.InstallNushellVersion, -1) + } else { + switch runtime.GOOS { + case "darwin": + switch runtime.GOARCH { + case "arm64": + // https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-darwin-full.tar.gz + assetName = fmt.Sprintf("nu-%s-aarch64-darwin-full.tar.gz", conf.InstallNushellVersion) + default: + a.Logger.Debugln("InstallNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) + return + } + case "linux": + switch runtime.GOARCH { + case "amd64": + // https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-x86_64-linux-musl-full.tar.gz + assetName = fmt.Sprintf("nu-%s-x86_64-linux-musl-full.tar.gz", conf.InstallNushellVersion) + case "arm64": + // https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-linux-gnu-full.tar.gz + assetName = fmt.Sprintf("nu-%s-aarch64-linux-gnu-full.tar.gz", conf.InstallNushellVersion) + default: + a.Logger.Debugln("InstallNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) + return + } + default: + a.Logger.Debugln("InstallNushell(): Unsupported OS:", runtime.GOOS) + return + } + url = fmt.Sprintf("https://github.com/nushell/nushell/releases/download/%s/%s", conf.InstallNushellVersion, assetName) + } + a.Logger.Debugln("InstallNushell(): Nu download url:", url) + + tmpDir, err := os.MkdirTemp("", "trmm") + if err != nil { + a.Logger.Errorln("InstallNushell(): Error creating temp directory:", err) + return + } + defer func(path string) { + err := os.RemoveAll(path) + if err != nil { + a.Logger.Errorln("InstallNushell(): Error removing temp directory:", err) + } + }(tmpDir) + + tmpAssetName := filepath.Join(tmpDir, assetName) + a.Logger.Debugln("InstallNushell(): tmpAssetName:", tmpAssetName) + + rClient := resty.New() + rClient.SetTimeout(20 * time.Minute) + rClient.SetRetryCount(10) + rClient.SetRetryWaitTime(1 * time.Minute) + rClient.SetRetryMaxWaitTime(15 * time.Minute) + if len(a.Proxy) > 0 { + rClient.SetProxy(a.Proxy) + } + + r, err := rClient.R().SetOutput(tmpAssetName).Get(url) + if err != nil { + a.Logger.Errorln("InstallNushell(): Unable to download nu:", err) + return + } + if r.IsError() { + a.Logger.Errorln("InstallNushell(): Unable to download nu. Status code:", r.StatusCode()) + return + } + + if conf.InstallNushellUrl != "" { + // InstallNushellUrl is not compressed. + err = copyFile(path.Join(tmpDir, tmpAssetName), a.NuBin) + if err != nil { + a.Logger.Errorln("InstallNushell(): Failed to copy nu file to install dir:", err) + return + } + } else { + // GitHub asset is tar.gz compressed. + targzDirName, err = a.ExtractTarGz(tmpAssetName, tmpDir) + if err != nil { + a.Logger.Errorln("InstallNushell(): Failed to extract downloaded tar.gz file:", err) + return + } + + err = copyFile(path.Join(tmpDir, targzDirName, "nu"), a.NuBin) + if err != nil { + a.Logger.Errorln("InstallNushell(): Failed to copy nu file to install dir:", err) + return + } + } + + err = os.Chmod(a.NuBin, 0755) + if err != nil { + a.Logger.Errorln("InstallNushell(): Failed to chmod nu binary:", err) + return + } + +} + +// InstallDeno will download deno from GitHub and install (copy) it to nixAgentBinDir +func (a *Agent) InstallDeno(force bool) { + conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI()) + if !conf.InstallDeno { + return + } + + if trmm.FileExists(a.DenoBin) { + if force { + a.Logger.Debugln(a.NuBin, "InstallDeno(): Forced install. Removing deno binary.") + err := os.Remove(a.DenoBin) + if err != nil { + a.Logger.Errorln("InstallDeno(): Error removing deno binary:", err) + return + } + } else { + return + } + } + + if !trmm.FileExists(nixAgentBinDir) { + err := os.MkdirAll(nixAgentBinDir, 0755) + if err != nil { + a.Logger.Errorln("InstallDeno(): Error creating nixAgentBinDir:", err) + return + } + } + + var ( + assetName string + url string + ) + + if conf.InstallDenoUrl != "" { + url = conf.InstallDenoUrl + url = strings.Replace(url, "{OS}", runtime.GOOS, -1) + url = strings.Replace(url, "{ARCH}", runtime.GOARCH, -1) + url = strings.Replace(url, "{VERSION}", conf.InstallDenoVersion, -1) + } else { + switch runtime.GOOS { + case "darwin": + switch runtime.GOARCH { + case "arm64": + // https://github.com/denoland/deno/releases/download/v1.38.2/deno-aarch64-apple-darwin.zip + assetName = fmt.Sprintf("deno-aarch64-apple-darwin.zip") + case "amd64": + // https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-apple-darwin.zip + assetName = fmt.Sprintf("deno-x86_64-apple-darwin.zip") + default: + a.Logger.Debugln("InstallDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) + return + } + case "linux": + switch runtime.GOARCH { + case "amd64": + // https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-unknown-linux-gnu.zip + assetName = fmt.Sprintf("deno-x86_64-unknown-linux-gnu.zip") + default: + a.Logger.Debugln("InstallDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) + return + } + default: + a.Logger.Debugln("InstallDeno(): Unsupported OS:", runtime.GOOS) + return + } + url = fmt.Sprintf("https://github.com/denoland/deno/releases/download/%s/%s", conf.InstallDenoVersion, assetName) + } + a.Logger.Debugln("InstallDeno(): Deno download url:", url) + + tmpDir, err := os.MkdirTemp("", "trmm") + if err != nil { + a.Logger.Errorln("InstallDeno(): Error creating temp directory:", err) + return + } + defer func(path string) { + err := os.RemoveAll(path) + if err != nil { + a.Logger.Errorln("InstallDeno(): Error removing temp directory:", err) + } + }(tmpDir) + + tmpAssetName := filepath.Join(tmpDir, assetName) + a.Logger.Debugln("InstallDeno(): tmpAssetName:", tmpAssetName) + + rClient := resty.New() + rClient.SetTimeout(20 * time.Minute) + rClient.SetRetryCount(10) + rClient.SetRetryWaitTime(1 * time.Minute) + rClient.SetRetryMaxWaitTime(15 * time.Minute) + if len(a.Proxy) > 0 { + rClient.SetProxy(a.Proxy) + } + + r, err := rClient.R().SetOutput(tmpAssetName).Get(url) + if err != nil { + a.Logger.Errorln("InstallDeno(): Unable to download deno:", err) + return + } + if r.IsError() { + a.Logger.Errorln("InstallDeno(): Unable to download deno. Status code:", r.StatusCode()) + return + } + + if conf.InstallDenoUrl != "" { + // InstallDenoUrl is not compressed. + err = copyFile(path.Join(tmpDir, tmpAssetName), a.DenoBin) + if err != nil { + a.Logger.Errorln("InstallDeno(): Failed to copy deno file to install dir:", err) + return + } + } else { + // GitHub asset is zip compressed. + err = Unzip(tmpAssetName, tmpDir) + if err != nil { + a.Logger.Errorln("InstallDeno(): Failed to unzip downloaded zip file:", err) + return + } + + err = copyFile(path.Join(tmpDir, "deno"), a.DenoBin) + if err != nil { + a.Logger.Errorln("InstallDeno(): Failed to copy deno file to install dir:", err) + return + } + } + + err = os.Chmod(a.DenoBin, 0755) + if err != nil { + a.Logger.Errorln("InstallDeno(): Failed to chmod deno binary:", err) + return + } + +} + +// GetAgentCheckInConfig will get the agent configuration from the server. +// The Windows agent stores the configuration in the registry. The UNIX agent does not store the config. +// @return AgentCheckInConfig func (a *Agent) GetAgentCheckInConfig(ret AgentCheckInConfig) AgentCheckInConfig { + // TODO: Persist the config to disk. return ret } +// windows only below TODO add into stub file func (a *Agent) PlatVer() (string, error) { return "", nil } func (a *Agent) SendSoftware() {} @@ -553,235 +878,6 @@ func GetServiceStatus(name string) (string, error) { return "", nil } func (a *Agent) GetPython(force bool) {} -// GetNushell will download nushell from GitHub and install (copy) it to nixAgentBinDir -func (a *Agent) GetNushell(force bool) { - if trmm.FileExists(a.NuBin) { - if force { - err := os.Remove(a.NuBin) - if err != nil { - a.Logger.Errorln("GetNushell(): Error removing nu binary:", err) - return - } - } else { - return - } - } - - if !trmm.FileExists(nixAgentBinDir) { - err := os.MkdirAll(nixAgentBinDir, 0755) - if err != nil { - a.Logger.Errorln("GetNushell(): Error creating nixAgentBinDir:", err) - return - } - } - - var ( - assetName string - url string - targzDirName string - ) - - switch runtime.GOOS { - case "darwin": - switch runtime.GOARCH { - case "arm64": - // https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-darwin-full.tar.gz - assetName = fmt.Sprintf("nu-%s-aarch64-darwin-full.tar.gz", nuVersion) - default: - a.Logger.Debugln("GetNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) - return - } - case "linux": - switch runtime.GOARCH { - case "amd64": - // https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-x86_64-linux-musl-full.tar.gz - assetName = fmt.Sprintf("nu-%s-x86_64-linux-musl-full.tar.gz", nuVersion) - case "arm64": - // https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-linux-gnu-full.tar.gz - assetName = fmt.Sprintf("nu-%s-aarch64-linux-gnu-full.tar.gz", nuVersion) - default: - a.Logger.Debugln("GetNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) - return - } - default: - a.Logger.Debugln("GetNushell(): Unsupported OS:", runtime.GOOS) - return - } - url = fmt.Sprintf("https://github.com/nushell/nushell/releases/download/%s/%s", nuVersion, assetName) - a.Logger.Debugln("GetNushell(): Nu download url:", url) - - tmpDir, err := os.MkdirTemp("", "trmm") - if err != nil { - a.Logger.Errorln("GetNushell(): Error creating temp directory:", err) - return - } - defer func(path string) { - err := os.RemoveAll(path) - if err != nil { - a.Logger.Errorln("GetNushell(): Error removing temp directory:", err) - } - }(tmpDir) - - tmpAssetName := filepath.Join(tmpDir, assetName) - a.Logger.Debugln("GetNushell(): tmpAssetName:", tmpAssetName) - - rClient := resty.New() - rClient.SetTimeout(20 * time.Minute) - rClient.SetRetryCount(10) - rClient.SetRetryWaitTime(1 * time.Minute) - rClient.SetRetryMaxWaitTime(15 * time.Minute) - if len(a.Proxy) > 0 { - rClient.SetProxy(a.Proxy) - } - - r, err := rClient.R().SetOutput(tmpAssetName).Get(url) - if err != nil { - a.Logger.Errorln("GetNushell(): Unable to download nu from github.", err) - return - } - if r.IsError() { - a.Logger.Errorln("GetNushell(): Unable to download nu from github. Status code", r.StatusCode()) - return - } - - targzDirName, err = a.ExtractTarGz(tmpAssetName, tmpDir) - if err != nil { - a.Logger.Errorln("GetNushell(): Failed to extract downloaded tar.gz file:", err) - return - } - - err = copyFile(path.Join(tmpDir, targzDirName, "nu"), a.NuBin) - if err != nil { - a.Logger.Errorln("GetNushell(): Failed to copy nu file to install dir:", err) - return - } - - err = os.Chmod(a.NuBin, 0755) - if err != nil { - a.Logger.Errorln("GetNushell(): Failed to chmod nu binary:", err) - return - } - -} - -// GetDeno will download deno from GitHub and install (copy) it to nixAgentBinDir -func (a *Agent) GetDeno(force bool) { - if trmm.FileExists(a.DenoBin) { - if force { - err := os.Remove(a.DenoBin) - if err != nil { - a.Logger.Errorln("GetDeno(): Error removing deno binary:", err) - return - } - } else { - return - } - } - - if !trmm.FileExists(nixAgentBinDir) { - err := os.MkdirAll(nixAgentBinDir, 0755) - if err != nil { - a.Logger.Errorln("GetDeno(): Error creating nixAgentBinDir:", err) - return - } - } - - var ( - assetName string - url string - ) - - switch runtime.GOOS { - case "darwin": - switch runtime.GOARCH { - case "arm64": - // https://github.com/denoland/deno/releases/download/v1.38.2/deno-aarch64-apple-darwin.zip - assetName = fmt.Sprintf("deno-aarch64-apple-darwin.zip") - case "amd64": - // https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-apple-darwin.zip - assetName = fmt.Sprintf("deno-x86_64-apple-darwin.zip") - default: - a.Logger.Debugln("GetDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) - return - } - case "linux": - switch runtime.GOARCH { - case "amd64": - // https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-unknown-linux-gnu.zip - assetName = fmt.Sprintf("deno-x86_64-unknown-linux-gnu.zip") - default: - a.Logger.Debugln("GetDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) - return - } - default: - a.Logger.Debugln("GetDeno(): Unsupported OS:", runtime.GOOS) - return - } - url = fmt.Sprintf("https://github.com/denoland/deno/releases/download/%s/%s", denoVersion, assetName) - a.Logger.Debugln("GetDeno(): Deno download url:", url) - - tmpDir, err := os.MkdirTemp("", "trmm") - if err != nil { - a.Logger.Errorln("GetDeno(): Error creating temp directory:", err) - return - } - defer func(path string) { - err := os.RemoveAll(path) - if err != nil { - a.Logger.Errorln("GetDeno(): Error removing temp directory:", err) - } - }(tmpDir) - - tmpAssetName := filepath.Join(tmpDir, assetName) - a.Logger.Debugln("GetDeno(): tmpAssetName:", tmpAssetName) - - if !trmm.FileExists(nixAgentBinDir) { - err = os.MkdirAll(nixAgentBinDir, 0755) - if err != nil { - a.Logger.Errorln("GetDeno(): Error creating nixAgentBinDir:", err) - return - } - } - - rClient := resty.New() - rClient.SetTimeout(20 * time.Minute) - rClient.SetRetryCount(10) - rClient.SetRetryWaitTime(1 * time.Minute) - rClient.SetRetryMaxWaitTime(15 * time.Minute) - if len(a.Proxy) > 0 { - rClient.SetProxy(a.Proxy) - } - - r, err := rClient.R().SetOutput(tmpAssetName).Get(url) - if err != nil { - a.Logger.Errorln("GetDeno(): Unable to download deno from github.", err) - return - } - if r.IsError() { - a.Logger.Errorln("GetDeno(): Unable to download deno from github. Status code", r.StatusCode()) - return - } - - err = Unzip(tmpAssetName, tmpDir) - if err != nil { - a.Logger.Errorln("GetDeno(): Failed to unzip downloaded zip file:", err) - return - } - - err = copyFile(path.Join(tmpDir, "deno"), a.DenoBin) - if err != nil { - a.Logger.Errorln("GetDeno(): Failed to copy deno file to install dir:", err) - return - } - - err = os.Chmod(a.DenoBin, 0755) - if err != nil { - a.Logger.Errorln("GetDeno(): Failed to chmod deno binary:", err) - return - } - -} - type SchedTask struct{ Name string } func (a *Agent) PatchMgmnt(enable bool) error { return nil } diff --git a/agent/agent_windows.go b/agent/agent_windows.go index c61a29a..cc22cbf 100644 --- a/agent/agent_windows.go +++ b/agent/agent_windows.go @@ -92,7 +92,7 @@ func NewAgentConfig() *rmm.AgentConfig { } } -func (a *Agent) RunScript(code string, shell string, args []string, timeout int, runasuser bool, envVars []string) (stdout, stderr string, exitcode int, e error) { +func (a *Agent) RunScript(code string, shell string, args []string, timeout int, runasuser bool, envVars []string, nushellEnableConfig bool, denoDefaultPermissions string) (stdout, stderr string, exitcode int, e error) { content := []byte(code) @@ -158,7 +158,18 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int, exe = tmpfn.Name() case "nushell": exe = a.NuBin - cmdArgs = []string{"--no-config-file", tmpfn.Name()} + var nushellArgs []string + if nushellEnableConfig { + nushellArgs = []string{ + "--config", + path.Join(a.ProgramDir, "etc", "nushell", "config.nu"), + "--env-config", + path.Join(a.ProgramDir, "etc", "nushell", "env.nu"), + } + } else { + nushellArgs = []string{"--no-config-file"} + } + cmdArgs = append(nushellArgs, tmpfn.Name()) if !trmm.FileExists(a.NuBin) { a.Logger.Errorln("RunScript(): Executable does not exist. Install Nu and try again:", a.NuBin) err := errors.New("File Not Found: " + a.NuBin) @@ -177,6 +188,8 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int, // https://docs.deno.com/runtime/manual/basics/permissions#permissions-list // DENO_PERMISSIONS is not an official environment variable. // https://docs.deno.com/runtime/manual/basics/env_variables + // DENO_DEFAULT_PERMISSIONS is used if not found in the environment variables. + found := false for i, v := range envVars { if strings.HasPrefix(v, "DENO_PERMISSIONS=") { permissions := strings.Split(v, "=")[1] @@ -184,12 +197,13 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int, // Remove the DENO_PERMISSIONS variable from the environment variables slice. // It's possible more variables may exist with the same prefix. envVars = append(envVars[:i], envVars[i+1:]...) + found = true break } } - - // Can't append a variadic slice after a string arg. - // https://pkg.go.dev/builtin#append + if !found && denoDefaultPermissions != "" { + cmdArgs = append(cmdArgs, strings.Split(denoDefaultPermissions, " ")...) + } cmdArgs = append(cmdArgs, tmpfn.Name()) } @@ -879,14 +893,20 @@ func (a *Agent) GetPython(force bool) { } } -// GetNushell will download nushell from GitHub and install (copy) it to ProgramDir\bin, where ProgramDir is +// InstallNushell will download nushell from GitHub and install (copy) it to ProgramDir\bin, where ProgramDir is // initialized to C:\Program Files\TacticalAgent -func (a *Agent) GetNushell(force bool) { +func (a *Agent) InstallNushell(force bool) { + conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI()) + if !conf.InstallNushell { + return + } + if trmm.FileExists(a.NuBin) { if force { + a.Logger.Debugln(a.NuBin, "InstallNushell(): Forced install. Removing nu.exe binary.") err := os.Remove(a.NuBin) if err != nil { - a.Logger.Errorln("GetNushell(): Error removing nu binary:", err) + a.Logger.Errorln("InstallNushell(): Error removing nu.exe binary:", err) return } } else { @@ -898,50 +918,96 @@ func (a *Agent) GetNushell(force bool) { if !trmm.FileExists(programBinDir) { err := os.MkdirAll(programBinDir, 0755) if err != nil { - a.Logger.Errorln("GetNushell(): Error creating Program Files bin folder:", err) + a.Logger.Errorln("InstallNushell(): Error creating Program Files bin folder:", err) return } } + if conf.NushellEnableConfig { + // Create 0-byte config files for Nushell + nushellPath := path.Join(a.ProgramDir, "etc", "nushell") + nushellConfig := path.Join(nushellPath, "config.nu") + nushellEnv := path.Join(nushellPath, "env.nu") + if !trmm.FileExists(nushellPath) { + err := os.MkdirAll(nushellPath, 0755) + if err != nil { + a.Logger.Errorln("InstallNushell(): Error creating Program Files/nushell:", err) + return + } + } + + if !trmm.FileExists(nushellConfig) { + _, err := os.Create(nushellConfig) + if err != nil { + a.Logger.Errorln("InstallNushell(): Error creating nushell config.nu:", err) + return + } + err = os.Chmod(nushellConfig, 0744) + if err != nil { + a.Logger.Errorln("InstallNushell(): Error changing permissions for nushell config.nu:", err) + return + } + } + if !trmm.FileExists(nushellEnv) { + _, err := os.Create(nushellEnv) + if err != nil { + a.Logger.Errorln("InstallNushell(): Error creating nushell env.nu:", err) + return + } + err = os.Chmod(nushellEnv, 0744) + if err != nil { + a.Logger.Errorln("InstallNushell(): Error changing permissions for nushell env.nu:", err) + return + } + } + } + var ( assetName string url string ) - switch runtime.GOOS { - case "windows": - switch runtime.GOARCH { - case "amd64": - // https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-x86_64-windows-msvc-full.zip - assetName = fmt.Sprintf("nu-%s-x86_64-windows-msvc-full.zip", nuVersion) - case "arm64": - // https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-windows-msvc-full.zip - assetName = fmt.Sprintf("nu-%s-aarch64-windows-msvc-full.zip", nuVersion) + if conf.InstallNushellUrl != "" { + url = conf.InstallNushellUrl + url = strings.Replace(url, "{OS}", runtime.GOOS, -1) + url = strings.Replace(url, "{ARCH}", runtime.GOARCH, -1) + url = strings.Replace(url, "{VERSION}", conf.InstallNushellVersion, -1) + } else { + switch runtime.GOOS { + case "windows": + switch runtime.GOARCH { + case "amd64": + // https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-x86_64-windows-msvc-full.zip + assetName = fmt.Sprintf("nu-%s-x86_64-windows-msvc-full.zip", conf.InstallNushellVersion) + case "arm64": + // https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-windows-msvc-full.zip + assetName = fmt.Sprintf("nu-%s-aarch64-windows-msvc-full.zip", conf.InstallNushellVersion) + default: + a.Logger.Debugln("InstallNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) + return + } default: - a.Logger.Debugln("GetNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) + a.Logger.Debugln("InstallNushell(): Unsupported OS:", runtime.GOOS) return } - default: - a.Logger.Debugln("GetNushell(): Unsupported OS:", runtime.GOOS) - return + url = fmt.Sprintf("https://github.com/nushell/nushell/releases/download/%s/%s", conf.InstallNushellVersion, assetName) } - url = fmt.Sprintf("https://github.com/nushell/nushell/releases/download/%s/%s", nuVersion, assetName) - a.Logger.Debugln("GetNushell(): Nu download url:", url) + a.Logger.Debugln("InstallNushell(): Nu download url:", url) tmpDir, err := os.MkdirTemp("", "trmm") if err != nil { - a.Logger.Errorln("GetNushell(): Error creating temp directory:", err) + a.Logger.Errorln("InstallNushell(): Error creating temp directory:", err) return } defer func(path string) { err := os.RemoveAll(path) if err != nil { - a.Logger.Errorln("GetNushell(): Error removing temp directory:", err) + a.Logger.Errorln("InstallNushell(): Error removing temp directory:", err) } }(tmpDir) tmpAssetName := filepath.Join(tmpDir, assetName) - a.Logger.Debugln("GetNushell(): tmpAssetName:", tmpAssetName) + a.Logger.Debugln("InstallNushell(): tmpAssetName:", tmpAssetName) rClient := resty.New() rClient.SetTimeout(20 * time.Minute) @@ -954,35 +1020,50 @@ func (a *Agent) GetNushell(force bool) { r, err := rClient.R().SetOutput(tmpAssetName).Get(url) if err != nil { - a.Logger.Errorln("GetNushell(): Unable to download nu from github.", err) + a.Logger.Errorln("InstallNushell(): Unable to download nu:", err) return } if r.IsError() { - a.Logger.Errorln("GetNushell(): Unable to download nu from github. Status code", r.StatusCode()) + a.Logger.Errorln("InstallNushell(): Unable to download nu. Status code:", r.StatusCode()) return } - err = Unzip(tmpAssetName, tmpDir) - if err != nil { - a.Logger.Errorln("GetNushell(): Failed to unzip downloaded zip file:", err) - return - } + if conf.InstallNushellUrl != "" { + // InstallNushellUrl is not compressed. + err = copyFile(path.Join(tmpDir, tmpAssetName), a.NuBin) + if err != nil { + a.Logger.Errorln("InstallNushell(): Failed to copy nu file to install dir:", err) + return + } + } else { + err = Unzip(tmpAssetName, tmpDir) + if err != nil { + a.Logger.Errorln("InstallNushell(): Failed to unzip downloaded zip file:", err) + return + } - err = copyFile(path.Join(tmpDir, "nu.exe"), a.NuBin) - if err != nil { - a.Logger.Errorln("GetNushell(): Failed to copy nu.exe file to install dir:", err) - return + err = copyFile(path.Join(tmpDir, "nu.exe"), a.NuBin) + if err != nil { + a.Logger.Errorln("InstallNushell(): Failed to copy nu.exe file to install dir:", err) + return + } } } -// GetDeno will download deno from GitHub and install (copy) it to nixAgentBinDir -func (a *Agent) GetDeno(force bool) { +// InstallDeno will download deno from GitHub and install (copy) it to ProgramDir\bin, where ProgramDir is +// initialized to C:\Program Files\TacticalAgent +func (a *Agent) InstallDeno(force bool) { + conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI()) + if !conf.InstallDeno { + return + } + if trmm.FileExists(a.DenoBin) { if force { err := os.Remove(a.DenoBin) if err != nil { - a.Logger.Errorln("GetDeno(): Error removing deno binary:", err) + a.Logger.Errorln("InstallDeno(): Error removing deno binary:", err) return } } else { @@ -994,7 +1075,7 @@ func (a *Agent) GetDeno(force bool) { if !trmm.FileExists(programBinDir) { err := os.MkdirAll(programBinDir, 0755) if err != nil { - a.Logger.Errorln("GetDeno(): Error creating Program Files bin folder:", err) + a.Logger.Errorln("InstallDeno(): Error creating Program Files bin folder:", err) return } } @@ -1004,45 +1085,44 @@ func (a *Agent) GetDeno(force bool) { url string ) - switch runtime.GOOS { - case "windows": - switch runtime.GOARCH { - case "amd64": - // https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-pc-windows-msvc.zip - assetName = fmt.Sprintf("deno-x86_64-pc-windows-msvc.zip") + if conf.InstallDenoUrl != "" { + url = conf.InstallDenoUrl + url = strings.Replace(url, "{OS}", runtime.GOOS, -1) + url = strings.Replace(url, "{ARCH}", runtime.GOARCH, -1) + url = strings.Replace(url, "{VERSION}", conf.InstallDenoVersion, -1) + } else { + switch runtime.GOOS { + case "windows": + switch runtime.GOARCH { + case "amd64": + // https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-pc-windows-msvc.zip + assetName = fmt.Sprintf("deno-x86_64-pc-windows-msvc.zip") + default: + a.Logger.Debugln("InstallDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) + return + } default: - a.Logger.Debugln("GetDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) + a.Logger.Debugln("InstallDeno(): Unsupported OS:", runtime.GOOS) return } - default: - a.Logger.Debugln("GetDeno(): Unsupported OS:", runtime.GOOS) - return + url = fmt.Sprintf("https://github.com/denoland/deno/releases/download/%s/%s", conf.InstallDenoVersion, assetName) } - url = fmt.Sprintf("https://github.com/denoland/deno/releases/download/%s/%s", denoVersion, assetName) - a.Logger.Debugln("GetDeno(): Deno download url:", url) + a.Logger.Debugln("InstallDeno(): Deno download url:", url) tmpDir, err := os.MkdirTemp("", "trmm") if err != nil { - a.Logger.Errorln("GetDeno(): Error creating temp directory:", err) + a.Logger.Errorln("InstallDeno(): Error creating temp directory:", err) return } defer func(path string) { err := os.RemoveAll(path) if err != nil { - a.Logger.Errorln("GetDeno(): Error removing temp directory:", err) + a.Logger.Errorln("InstallDeno(): Error removing temp directory:", err) } }(tmpDir) tmpAssetName := filepath.Join(tmpDir, assetName) - a.Logger.Debugln("GetDeno(): tmpAssetName:", tmpAssetName) - - if !trmm.FileExists(nixAgentBinDir) { - err = os.MkdirAll(nixAgentBinDir, 0755) - if err != nil { - a.Logger.Errorln("GetDeno(): Error creating nixAgentBinDir:", err) - return - } - } + a.Logger.Debugln("InstallDeno(): tmpAssetName:", tmpAssetName) rClient := resty.New() rClient.SetTimeout(20 * time.Minute) @@ -1055,24 +1135,34 @@ func (a *Agent) GetDeno(force bool) { r, err := rClient.R().SetOutput(tmpAssetName).Get(url) if err != nil { - a.Logger.Errorln("GetDeno(): Unable to download deno from github.", err) + a.Logger.Errorln("InstallDeno(): Unable to download deno:", err) return } if r.IsError() { - a.Logger.Errorln("GetDeno(): Unable to download deno from github. Status code", r.StatusCode()) + a.Logger.Errorln("InstallDeno(): Unable to download deno. Status code:", r.StatusCode()) return } - err = Unzip(tmpAssetName, tmpDir) - if err != nil { - a.Logger.Errorln("GetDeno(): Failed to unzip downloaded zip file:", err) - return - } + if conf.InstallDenoUrl != "" { + // InstallDenoUrl is not compressed. + err = copyFile(path.Join(tmpDir, tmpAssetName), a.DenoBin) + if err != nil { + a.Logger.Errorln("InstallDeno(): Failed to copy deno file to install dir:", err) + return + } + } else { + // GitHub asset is zip compressed. + err = Unzip(tmpAssetName, tmpDir) + if err != nil { + a.Logger.Errorln("InstallDeno(): Failed to unzip downloaded zip file:", err) + return + } - err = copyFile(path.Join(tmpDir, "deno.exe"), a.DenoBin) - if err != nil { - a.Logger.Errorln("GetDeno(): Failed to copy deno.exe file to install dir:", err) - return + err = copyFile(path.Join(tmpDir, "deno.exe"), a.DenoBin) + if err != nil { + a.Logger.Errorln("InstallDeno(): Failed to copy deno.exe file to install dir:", err) + return + } } } diff --git a/agent/checks.go b/agent/checks.go index 930e947..5e0905d 100644 --- a/agent/checks.go +++ b/agent/checks.go @@ -169,7 +169,7 @@ type ScriptCheckResult struct { // ScriptCheck runs either bat, powershell or python script func (a *Agent) ScriptCheck(data rmm.Check, r *resty.Client) { start := time.Now() - stdout, stderr, retcode, _ := a.RunScript(data.Script.Code, data.Script.Shell, data.ScriptArgs, data.Timeout, data.Script.RunAsUser, data.EnvVars) + stdout, stderr, retcode, _ := a.RunScript(data.Script.Code, data.Script.Shell, data.ScriptArgs, data.Timeout, data.Script.RunAsUser, data.EnvVars, data.NushellEnableConfig, data.DenoDefaultPermissions) payload := ScriptCheckResult{ ID: data.CheckPK, diff --git a/agent/choco_windows.go b/agent/choco_windows.go index f75b15f..7019785 100644 --- a/agent/choco_windows.go +++ b/agent/choco_windows.go @@ -45,7 +45,7 @@ func (a *Agent) InstallChoco() { return } - _, _, exitcode, err := a.RunScript(string(r.Body()), "powershell", []string{}, 900, false, []string{}) + _, _, exitcode, err := a.RunScript(string(r.Body()), "powershell", []string{}, 900, false, []string{}, false, "") if err != nil { a.Logger.Debugln(err) a.rClient.R().SetBody(result).Post(url) diff --git a/agent/embed_darwin.go b/agent/embed_darwin.go index 6a42a6d..c69225a 100644 --- a/agent/embed_darwin.go +++ b/agent/embed_darwin.go @@ -20,5 +20,5 @@ import _ "embed" var ventura_mesh_fix string func (a *Agent) FixVenturaMesh() { - a.RunScript(ventura_mesh_fix, "foo", []string{}, 45, false, []string{}) + a.RunScript(ventura_mesh_fix, "foo", []string{}, 45, false, []string{}, false, "") } diff --git a/agent/rpc.go b/agent/rpc.go index 03b1508..a58e6f5 100644 --- a/agent/rpc.go +++ b/agent/rpc.go @@ -26,22 +26,24 @@ import ( ) type NatsMsg struct { - Func string `json:"func"` - Timeout int `json:"timeout"` - Data map[string]string `json:"payload"` - ScriptArgs []string `json:"script_args"` - ProcPID int32 `json:"procpid"` - TaskPK int `json:"taskpk"` - ScheduledTask SchedTask `json:"schedtaskpayload"` - RecoveryCommand string `json:"recoverycommand"` - UpdateGUIDs []string `json:"guids"` - ChocoProgName string `json:"choco_prog_name"` - PendingActionPK int `json:"pending_action_pk"` - PatchMgmt bool `json:"patch_mgmt"` - ID int `json:"id"` - Code string `json:"code"` - RunAsUser bool `json:"run_as_user"` - EnvVars []string `json:"env_vars"` + Func string `json:"func"` + Timeout int `json:"timeout"` + Data map[string]string `json:"payload"` + ScriptArgs []string `json:"script_args"` + ProcPID int32 `json:"procpid"` + TaskPK int `json:"taskpk"` + ScheduledTask SchedTask `json:"schedtaskpayload"` + RecoveryCommand string `json:"recoverycommand"` + UpdateGUIDs []string `json:"guids"` + ChocoProgName string `json:"choco_prog_name"` + PendingActionPK int `json:"pending_action_pk"` + PatchMgmt bool `json:"patch_mgmt"` + ID int `json:"id"` + Code string `json:"code"` + RunAsUser bool `json:"run_as_user"` + EnvVars []string `json:"env_vars"` + NushellEnableConfig bool `json:"nushell_enable_config"` + DenoDefaultPermissions string `json:"deno_default_permissions"` } var ( @@ -264,7 +266,7 @@ func (a *Agent) RunRPC() { var resultData rmm.RunScriptResp ret := codec.NewEncoderBytes(&resp, new(codec.MsgpackHandle)) start := time.Now() - stdout, stderr, retcode, err := a.RunScript(p.Data["code"], p.Data["shell"], p.ScriptArgs, p.Timeout, p.RunAsUser, p.EnvVars) + stdout, stderr, retcode, err := a.RunScript(p.Data["code"], p.Data["shell"], p.ScriptArgs, p.Timeout, p.RunAsUser, p.EnvVars, p.NushellEnableConfig, p.DenoDefaultPermissions) resultData.ExecTime = time.Since(start).Seconds() resultData.ID = p.ID @@ -294,7 +296,7 @@ func (a *Agent) RunRPC() { var retData rmm.RunScriptResp ret := codec.NewEncoderBytes(&resp, new(codec.MsgpackHandle)) start := time.Now() - stdout, stderr, retcode, err := a.RunScript(p.Data["code"], p.Data["shell"], p.ScriptArgs, p.Timeout, p.RunAsUser, p.EnvVars) + stdout, stderr, retcode, err := a.RunScript(p.Data["code"], p.Data["shell"], p.ScriptArgs, p.Timeout, p.RunAsUser, p.EnvVars, p.NushellEnableConfig, p.DenoDefaultPermissions) retData.ExecTime = time.Since(start).Seconds() if err != nil { @@ -438,9 +440,9 @@ func (a *Agent) RunRPC() { case "installpython": go a.GetPython(true) case "installnushell": - go a.GetNushell(true) + go a.InstallNushell(true) case "installdeno": - go a.GetDeno(true) + go a.InstallDeno(true) case "installchoco": go a.InstallChoco() case "installwithchoco": diff --git a/agent/svc.go b/agent/svc.go index b04bb9d..0827448 100644 --- a/agent/svc.go +++ b/agent/svc.go @@ -29,15 +29,23 @@ func (a *Agent) RunAsService(nc *nats.Conn) { } type AgentCheckInConfig struct { - Hello int `json:"checkin_hello"` - AgentInfo int `json:"checkin_agentinfo"` - WinSvc int `json:"checkin_winsvc"` - PubIP int `json:"checkin_pubip"` - Disks int `json:"checkin_disks"` - SW int `json:"checkin_sw"` - WMI int `json:"checkin_wmi"` - SyncMesh int `json:"checkin_syncmesh"` - LimitData bool `json:"limit_data"` + Hello int `json:"checkin_hello"` + AgentInfo int `json:"checkin_agentinfo"` + WinSvc int `json:"checkin_winsvc"` + PubIP int `json:"checkin_pubip"` + Disks int `json:"checkin_disks"` + SW int `json:"checkin_sw"` + WMI int `json:"checkin_wmi"` + SyncMesh int `json:"checkin_syncmesh"` + LimitData bool `json:"limit_data"` + InstallNushell bool `json:"install_nushell"` + InstallNushellVersion string `json:"install_nushell_version"` + InstallNushellUrl string `json:"install_nushell_url"` + NushellEnableConfig bool `json:"nushell_enable_config"` + InstallDeno bool `json:"install_deno"` + InstallDenoVersion string `json:"install_deno_version"` + InstallDenoUrl string `json:"install_deno_url"` + DenoDefaultPermissions string `json:"deno_default_permissions"` } func (a *Agent) AgentSvc(nc *nats.Conn) { @@ -49,8 +57,6 @@ func (a *Agent) AgentSvc(nc *nats.Conn) { a.Logger.Errorln("AgentSvc() createWinTempDir():", err) } } - a.GetNushell(false) - a.GetDeno(false) a.RunMigrations() @@ -64,8 +70,9 @@ func (a *Agent) AgentSvc(nc *nats.Conn) { a.CleanupAgentUpdates() } + // Windows has GetAgentCheckInConfig() while unix has a stub GetAgentCheckInConfig() conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI()) - a.Logger.Debugf("+%v\n", conf) + a.Logger.Debugf("AgentCheckInConf: %+v\n", conf) for _, s := range natsCheckin { if conf.LimitData && stringInSlice(s, limitNatsData) { continue @@ -75,6 +82,15 @@ func (a *Agent) AgentSvc(nc *nats.Conn) { } } + // The server conf check is also done in the functions to keep the parameters the same. + // Don't force a download when restarting the service. + if conf.InstallNushell { + a.InstallNushell(false) + } + if conf.InstallDeno { + a.InstallDeno(false) + } + go a.SyncMeshNodeID() time.Sleep(time.Duration(randRange(1, 3)) * time.Second) @@ -142,6 +158,14 @@ func (a *Agent) GetCheckInConfFromAPI() AgentCheckInConfig { ret.WMI = randRange(3000, 4000) ret.SyncMesh = randRange(800, 1200) ret.LimitData = false + ret.InstallNushell = false + ret.InstallNushellVersion = "" + ret.InstallNushellUrl = "" + ret.NushellEnableConfig = false + ret.InstallDeno = false + ret.InstallDenoVersion = "" + ret.InstallDenoUrl = "" + ret.DenoDefaultPermissions = "" } else { ret.Hello = r.Result().(*AgentCheckInConfig).Hello ret.AgentInfo = r.Result().(*AgentCheckInConfig).AgentInfo @@ -152,6 +176,14 @@ func (a *Agent) GetCheckInConfFromAPI() AgentCheckInConfig { ret.WMI = r.Result().(*AgentCheckInConfig).WMI ret.SyncMesh = r.Result().(*AgentCheckInConfig).SyncMesh ret.LimitData = r.Result().(*AgentCheckInConfig).LimitData + ret.InstallNushell = r.Result().(*AgentCheckInConfig).InstallNushell + ret.InstallNushellVersion = r.Result().(*AgentCheckInConfig).InstallNushellVersion + ret.InstallNushellUrl = r.Result().(*AgentCheckInConfig).InstallNushellUrl + ret.NushellEnableConfig = r.Result().(*AgentCheckInConfig).NushellEnableConfig + ret.InstallDeno = r.Result().(*AgentCheckInConfig).InstallDeno + ret.InstallDenoVersion = r.Result().(*AgentCheckInConfig).InstallDenoVersion + ret.InstallDenoUrl = r.Result().(*AgentCheckInConfig).InstallDenoUrl + ret.DenoDefaultPermissions = r.Result().(*AgentCheckInConfig).DenoDefaultPermissions } return ret } diff --git a/agent/tasks_windows.go b/agent/tasks_windows.go index ab199f4..a4db248 100644 --- a/agent/tasks_windows.go +++ b/agent/tasks_windows.go @@ -14,13 +14,13 @@ package agent import ( "encoding/json" "fmt" + "github.com/amidaware/taskmaster" "os" "path/filepath" "strings" "time" rmm "github.com/amidaware/rmmagent/shared" - "github.com/amidaware/taskmaster" "github.com/rickb777/date/period" ) @@ -59,7 +59,7 @@ func (a *Agent) RunTask(id int) error { action_start := time.Now() if action.ActionType == "script" { - stdout, stderr, retcode, err := a.RunScript(action.Code, action.Shell, action.Args, action.Timeout, action.RunAsUser, action.EnvVars) + stdout, stderr, retcode, err := a.RunScript(action.Code, action.Shell, action.Args, action.Timeout, action.RunAsUser, action.EnvVars, action.NushellEnableConfig, action.DenoDefaultPermissions) if err != nil { a.Logger.Debugln(err) diff --git a/main.go b/main.go index 0d46a62..4ccbdbf 100644 --- a/main.go +++ b/main.go @@ -117,10 +117,10 @@ func main() { fmt.Println(a.PublicIP()) case "getpython": a.GetPython(true) - case "getdeno": - a.GetDeno(true) - case "getnushell": - a.GetNushell(true) + case "installdeno": + a.InstallDeno(true) + case "installnushell": + a.InstallNushell(true) case "runmigrations": a.RunMigrations() case "recovermesh": diff --git a/shared/types.go b/shared/types.go index d7a6f24..f98beb9 100644 --- a/shared/types.go +++ b/shared/types.go @@ -157,29 +157,31 @@ type CheckInfo struct { } type Check struct { - Script Script `json:"script"` - AssignedTasks []AssignedTask `json:"assigned_tasks"` - CheckPK int `json:"id"` - CheckType string `json:"check_type"` - Status string `json:"status"` - Threshold int `json:"threshold"` - Disk string `json:"disk"` - IP string `json:"ip"` - ScriptArgs []string `json:"script_args"` - EnvVars []string `json:"env_vars"` - Timeout int `json:"timeout"` - ServiceName string `json:"svc_name"` - PassStartPending bool `json:"pass_if_start_pending"` - PassNotExist bool `json:"pass_if_svc_not_exist"` - RestartIfStopped bool `json:"restart_if_stopped"` - LogName string `json:"log_name"` - EventID int `json:"event_id"` - EventIDWildcard bool `json:"event_id_is_wildcard"` - EventType string `json:"event_type"` - EventSource string `json:"event_source"` - EventMessage string `json:"event_message"` - FailWhen string `json:"fail_when"` - SearchLastDays int `json:"search_last_days"` + Script Script `json:"script"` + AssignedTasks []AssignedTask `json:"assigned_tasks"` + CheckPK int `json:"id"` + CheckType string `json:"check_type"` + Status string `json:"status"` + Threshold int `json:"threshold"` + Disk string `json:"disk"` + IP string `json:"ip"` + ScriptArgs []string `json:"script_args"` + EnvVars []string `json:"env_vars"` + NushellEnableConfig bool `json:"nushell_enable_config"` + DenoDefaultPermissions string `json:"deno_default_permissions"` + Timeout int `json:"timeout"` + ServiceName string `json:"svc_name"` + PassStartPending bool `json:"pass_if_start_pending"` + PassNotExist bool `json:"pass_if_svc_not_exist"` + RestartIfStopped bool `json:"restart_if_stopped"` + LogName string `json:"log_name"` + EventID int `json:"event_id"` + EventIDWildcard bool `json:"event_id_is_wildcard"` + EventType string `json:"event_type"` + EventSource string `json:"event_source"` + EventMessage string `json:"event_message"` + FailWhen string `json:"fail_when"` + SearchLastDays int `json:"search_last_days"` } type AllChecks struct { @@ -188,15 +190,17 @@ type AllChecks struct { } type TaskAction struct { - ActionType string `json:"type"` - Command string `json:"command"` - Shell string `json:"shell"` - ScriptName string `json:"script_name"` - Code string `json:"code"` - Args []string `json:"script_args"` - Timeout int `json:"timeout"` - RunAsUser bool `json:"run_as_user"` - EnvVars []string `json:"env_vars"` + ActionType string `json:"type"` + Command string `json:"command"` + Shell string `json:"shell"` + ScriptName string `json:"script_name"` + Code string `json:"code"` + Args []string `json:"script_args"` + Timeout int `json:"timeout"` + RunAsUser bool `json:"run_as_user"` + EnvVars []string `json:"env_vars"` + NushellEnableConfig bool `json:"nushell_enable_config"` + DenoDefaultPermissions string `json:"deno_default_permissions"` } type AutomatedTask struct {