

























@@ -81,6 +81,10 @@ function assertMachineUserSystemctlArgs(args: string[], user: string, ...command
8181expect(args).toEqual(["--machine", `${user}@`, "--user", ...command]);
8282}
838384+function mockEffectiveUid(uid: number) {
85+vi.spyOn(process, "geteuid").mockReturnValue(uid);
86+}
87+8488async function readManagedServiceEnabled(env: NodeJS.ProcessEnv = { HOME: TEST_MANAGED_HOME }) {
8589vi.spyOn(fs, "access").mockResolvedValue(undefined);
8690return isSystemdServiceEnabled({ env });
@@ -190,6 +194,7 @@ describe("systemd availability", () => {
190194});
191195192196it("does not fall back to direct --user when machine scope fails under sudo", async () => {
197+mockEffectiveUid(0);
193198execFileMock.mockImplementationOnce((_cmd, args, _opts, cb) => {
194199assertMachineUserSystemctlArgs(args, "ai", "status");
195200cb(
@@ -205,6 +210,36 @@ describe("systemd availability", () => {
205210await expect(isSystemdUserServiceAvailable({ SUDO_USER: "ai" })).resolves.toBe(false);
206211expect(execFileMock).toHaveBeenCalledTimes(1);
207212});
213+214+it("does not let preserved USER suppress sudo-to-root machine scope", async () => {
215+mockEffectiveUid(0);
216+execFileMock.mockImplementationOnce((_cmd, args, _opts, cb) => {
217+assertMachineUserSystemctlArgs(args, "debian", "status");
218+cb(null, "", "");
219+});
220+221+await expect(
222+isSystemdUserServiceAvailable({
223+SUDO_USER: "debian",
224+USER: "root-env-stale",
225+LOGNAME: "root-env-stale",
226+}),
227+).resolves.toBe(true);
228+expect(execFileMock).toHaveBeenCalledTimes(1);
229+});
230+231+it("does not let stale SUDO_USER override a sudo-u target user scope", async () => {
232+mockEffectiveUid(1000);
233+execFileMock.mockImplementationOnce((_cmd, args, _opts, cb) => {
234+assertUserSystemctlArgs(args, "status");
235+cb(null, "", "");
236+});
237+238+await expect(
239+isSystemdUserServiceAvailable({ USER: "openclaw", SUDO_USER: "admin" }),
240+).resolves.toBe(true);
241+expect(execFileMock).toHaveBeenCalledTimes(1);
242+});
208243});
209244210245describe("isSystemdServiceEnabled", () => {
@@ -907,6 +942,51 @@ describe("systemd service install and uninstall", () => {
907942});
908943});
909944945+it("uses the sudo-u target user for install activation machine-scope retry", async () => {
946+await withNodeSystemdFixture(async ({ env }) => {
947+const installEnv = { ...env, USER: "openclaw", SUDO_USER: "admin" };
948+execFileMock
949+.mockImplementationOnce((_cmd, args, _opts, cb) => {
950+assertUserSystemctlArgs(args, "status");
951+cb(null, "", "");
952+})
953+.mockImplementationOnce((_cmd, args, _opts, cb) => {
954+assertUserSystemctlArgs(args, "daemon-reload");
955+cb(null, "", "");
956+})
957+.mockImplementationOnce((_cmd, args, _opts, cb) => {
958+assertUserSystemctlArgs(args, "enable", NODE_SERVICE);
959+cb(
960+createExecFileError("Failed to connect to bus: No medium found", {
961+stderr: "Failed to connect to bus: No medium found",
962+}),
963+"",
964+"",
965+);
966+})
967+.mockImplementationOnce((_cmd, args, _opts, cb) => {
968+assertMachineUserSystemctlArgs(args, "openclaw", "enable", NODE_SERVICE);
969+cb(null, "", "");
970+})
971+.mockImplementationOnce((_cmd, args, _opts, cb) => {
972+assertUserSystemctlArgs(args, "restart", NODE_SERVICE);
973+cb(null, "", "");
974+});
975+976+await installSystemdService({
977+env: installEnv,
978+stdout: { write: vi.fn() } as unknown as NodeJS.WritableStream,
979+programArguments: ["/usr/bin/openclaw", "node", "run"],
980+workingDirectory: "/tmp",
981+environment: {
982+OPENCLAW_SYSTEMD_UNIT: "openclaw-node",
983+},
984+});
985+986+expect(execFileMock).toHaveBeenCalledTimes(5);
987+});
988+});
989+910990it("surfaces install activation user-bus failures as systemd unavailable errors", async () => {
911991await withNodeSystemdFixture(async ({ env }) => {
912992vi.spyOn(os, "userInfo").mockImplementation(() => {
@@ -1066,6 +1146,7 @@ describe("systemd service control", () => {
10661146});
1067114710681148it("targets the sudo caller's user scope when SUDO_USER is set", async () => {
1149+mockEffectiveUid(0);
10691150execFileMock
10701151.mockImplementationOnce((_cmd, args, _opts, cb) => {
10711152assertMachineUserSystemctlArgs(args, "debian", "status");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。