fix(systemd): parse all inline environment assignments

This commit is contained in:
Peter Steinberger
2026-08-01 08:50:10 -07:00
parent ba2827f706
commit f6d5e2c19b
3 changed files with 35 additions and 4 deletions

View File

@@ -104,7 +104,7 @@ export function parseSystemdExecStart(value: string): string[] {
return splitArgsPreservingQuotes(value, { escapeMode: "backslash" });
}
export function parseSystemdEnvAssignment(raw: string): { key: string; value: string } | null {
function parseSystemdEnvAssignment(raw: string): { key: string; value: string } | null {
const trimmed = raw.trim();
if (!trimmed) {
return null;

View File

@@ -1265,6 +1265,39 @@ describe("readSystemdServiceExecStart", () => {
expect(command?.environmentValueSources?.OPENCLAW_GATEWAY_TOKEN).toBe("inline-and-file");
});
it("reads all inline assignments in order before EnvironmentFile overrides", async () => {
mockReadGatewayServiceFile(
[
"[Service]",
"ExecStart=/usr/bin/openclaw gateway run",
'Environment=PLAIN=first "QUOTED=value with spaces" REPEATED=first',
"Environment='REPEATED=last value' INLINE_FILE=inline",
"EnvironmentFile=%h/.openclaw/.env",
],
{
[`${TEST_SERVICE_HOME}/.openclaw/.env`]: ["INLINE_FILE=file", "FILE_ONLY=from-file"].join(
"\n",
),
},
);
const command = await readSystemdServiceExecStart({ HOME: TEST_SERVICE_HOME });
expect(command?.environment).toEqual({
PLAIN: "first",
QUOTED: "value with spaces",
REPEATED: "last value",
INLINE_FILE: "file",
FILE_ONLY: "from-file",
});
expect(command?.environmentValueSources).toEqual({
PLAIN: "inline",
QUOTED: "inline",
REPEATED: "inline",
INLINE_FILE: "inline-and-file",
FILE_ONLY: "file",
});
});
it("ignores missing optional EnvironmentFile entries", async () => {
await expectExecStartWithoutEnvironment("EnvironmentFile=-%h/.openclaw/missing.env");
});

View File

@@ -58,7 +58,6 @@ import {
} from "./systemd-unavailable.js";
import {
buildSystemdUnit,
parseSystemdEnvAssignment,
parseSystemdEnvAssignments,
parseSystemdExecStart,
renderSystemdEnvAssignment,
@@ -328,8 +327,7 @@ export async function readSystemdServiceExecStart(
workingDirectory = line.slice("WorkingDirectory=".length).trim();
} else if (line.startsWith("Environment=")) {
const raw = line.slice("Environment=".length).trim();
const parsed = parseSystemdEnvAssignment(raw);
if (parsed) {
for (const parsed of parseSystemdEnvAssignments(raw)) {
inlineEnvironment[parsed.key] = parsed.value;
}
} else if (line.startsWith("EnvironmentFile=")) {