fix: import missing shell env keys

This commit is contained in:
Peter Steinberger
2026-04-25 21:23:40 +01:00
parent 6a7b76e119
commit 607bc53ff3
3 changed files with 41 additions and 8 deletions

View File

@@ -632,6 +632,9 @@ Docs: https://docs.openclaw.ai
### Fixes
- Gateway/env: import each missing expected login-shell env var independently,
so an existing gateway token no longer prevents `env.shellEnv` from loading
plugin credentials such as `TWILIO_*` from `.profile`. Thanks @steipete.
- macOS/Gateway pairing: silently accept same-host native app
`metadata-upgrade` reconnects, so macOS patch-version changes update paired
metadata instead of spamming security audit warnings and `pairing required`

View File

@@ -137,8 +137,8 @@ describe("shell env fallback", () => {
).toBe(15000);
});
it("skips when already has an expected key", () => {
const env: NodeJS.ProcessEnv = { OPENAI_API_KEY: "set" };
it("skips when already has all expected keys", () => {
const env: NodeJS.ProcessEnv = { OPENAI_API_KEY: "set", DISCORD_BOT_TOKEN: "set" };
const exec = vi.fn(() => Buffer.from(""));
const res = runShellEnvFallback({
@@ -154,6 +154,37 @@ describe("shell env fallback", () => {
expect(exec).not.toHaveBeenCalled();
});
it("imports missing expected keys even when another expected key already exists", () => {
const env: NodeJS.ProcessEnv = { OPENCLAW_GATEWAY_TOKEN: "set" };
const exec = vi.fn(() =>
Buffer.from(
"OPENCLAW_GATEWAY_TOKEN=from-shell\0TWILIO_ACCOUNT_SID=AC123\0TWILIO_AUTH_TOKEN=secret\0TWILIO_FROM_NUMBER=+15550001234\0",
),
);
const res = runShellEnvFallback({
enabled: true,
env,
expectedKeys: [
"OPENCLAW_GATEWAY_TOKEN",
"TWILIO_ACCOUNT_SID",
"TWILIO_AUTH_TOKEN",
"TWILIO_FROM_NUMBER",
],
exec,
});
expect(res).toEqual({
ok: true,
applied: ["TWILIO_ACCOUNT_SID", "TWILIO_AUTH_TOKEN", "TWILIO_FROM_NUMBER"],
});
expect(env.OPENCLAW_GATEWAY_TOKEN).toBe("set");
expect(env.TWILIO_ACCOUNT_SID).toBe("AC123");
expect(env.TWILIO_AUTH_TOKEN).toBe("secret");
expect(env.TWILIO_FROM_NUMBER).toBe("+15550001234");
expect(exec).toHaveBeenCalledTimes(1);
});
it("treats explicitly empty env vars as intentional overrides", () => {
const env: NodeJS.ProcessEnv = { OPENAI_API_KEY: "" };
const exec = vi.fn(() => Buffer.from("OPENAI_API_KEY=from-shell\0"));

View File

@@ -220,8 +220,10 @@ export function loadShellEnvFallback(opts: ShellEnvFallbackOptions): ShellEnvFal
return { ok: true, applied: [], skippedReason: "disabled" };
}
const hasAnyKey = opts.expectedKeys.some((key) => hasExplicitEnvBinding(opts.env, key));
if (hasAnyKey) {
const missingExpectedKeys = opts.expectedKeys.filter(
(key) => !hasExplicitEnvBinding(opts.env, key),
);
if (missingExpectedKeys.length === 0) {
lastAppliedKeys = [];
return { ok: true, applied: [], skippedReason: "already-has-keys" };
}
@@ -238,10 +240,7 @@ export function loadShellEnvFallback(opts: ShellEnvFallbackOptions): ShellEnvFal
}
const applied: string[] = [];
for (const key of opts.expectedKeys) {
if (hasExplicitEnvBinding(opts.env, key)) {
continue;
}
for (const key of missingExpectedKeys) {
const value = probe.shellEnv.get(key);
if (!value?.trim()) {
continue;