diff --git a/CHANGELOG.md b/CHANGELOG.md index 0db27f20890..e36109cbb66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,6 +69,7 @@ Docs: https://docs.openclaw.ai - CLI/Daemon status TLS probe: use `wss://` and forward local TLS certificate fingerprint for TLS-enabled gateway daemon probes so `openclaw daemon status` works with `gateway.bind=lan` + `gateway.tls.enabled=true`. (#24234) thanks @liuy. - Podman/Default bind: change `run-openclaw-podman.sh` default gateway bind from `lan` to `loopback` and document explicit LAN opt-in with Control UI origin configuration. (#27491) thanks @robbyczgw-cla. - Daemon/macOS launchd: forward proxy env vars into supervised service environments, keep LaunchAgent `KeepAlive=true` semantics, and harden restart sequencing to `print -> bootout -> wait old pid exit -> bootstrap -> kickstart`. (#27276) thanks @frankekn. +- Daemon/macOS TLS certs: default LaunchAgent service env `NODE_EXTRA_CA_CERTS` to `/etc/ssl/cert.pem` (while preserving explicit overrides) so HTTPS clients no longer fail with local-issuer errors under launchd. (#27915) Thanks @Lukavyi. - Gateway/macOS restart-loop hardening: detect OpenClaw-managed supervisor markers during SIGUSR1 restart handoff, clean stale gateway PIDs before `/restart` launchctl/systemctl triggers, and set LaunchAgent `ThrottleInterval=60` to bound launchd retry storms during lock-release races. Landed from contributor PRs #27655 (@taw0002), #27448 (@Sid-Qin), and #27650 (@kevinWangSheng). (#27605, #27590, #26904, #26736) - Models/MiniMax auth header defaults: set `authHeader: true` for both onboarding-generated MiniMax API providers and implicit built-in MiniMax (`minimax`, `minimax-portal`) provider templates so first requests no longer fail with MiniMax `401 authentication_error` due to missing `Authorization` header. Landed from contributor PRs #27622 by @riccoyuanft and #27631 by @kevinWangSheng. (#27600, #15303) - Models/Google Antigravity IDs: normalize bare `gemini-3-pro`, `gemini-3.1-pro`, and `gemini-3-1-pro` model IDs to the default `-low` thinking tier so provider requests no longer fail with 404 when the tier suffix is omitted. (#24145) Thanks @byungsker. diff --git a/src/daemon/service-env.test.ts b/src/daemon/service-env.test.ts index ef8a64904a8..95dee4ecc1d 100644 --- a/src/daemon/service-env.test.ts +++ b/src/daemon/service-env.test.ts @@ -333,12 +333,18 @@ describe("buildServiceEnvironment", () => { const env = buildServiceEnvironment({ env: { HOME: "/home/user" }, port: 18789, + platform: "darwin", }); - if (process.platform === "darwin") { - expect(env.NODE_EXTRA_CA_CERTS).toBe("/etc/ssl/cert.pem"); - } else { - expect(env.NODE_EXTRA_CA_CERTS).toBeUndefined(); - } + expect(env.NODE_EXTRA_CA_CERTS).toBe("/etc/ssl/cert.pem"); + }); + + it("does not default NODE_EXTRA_CA_CERTS on non-macOS", () => { + const env = buildServiceEnvironment({ + env: { HOME: "/home/user" }, + port: 18789, + platform: "linux", + }); + expect(env.NODE_EXTRA_CA_CERTS).toBeUndefined(); }); it("respects user-provided NODE_EXTRA_CA_CERTS over the default", () => { @@ -388,12 +394,17 @@ describe("buildNodeServiceEnvironment", () => { it("defaults NODE_EXTRA_CA_CERTS to system cert bundle on macOS for node services", () => { const env = buildNodeServiceEnvironment({ env: { HOME: "/home/user" }, + platform: "darwin", }); - if (process.platform === "darwin") { - expect(env.NODE_EXTRA_CA_CERTS).toBe("/etc/ssl/cert.pem"); - } else { - expect(env.NODE_EXTRA_CA_CERTS).toBeUndefined(); - } + expect(env.NODE_EXTRA_CA_CERTS).toBe("/etc/ssl/cert.pem"); + }); + + it("does not default NODE_EXTRA_CA_CERTS on non-macOS for node services", () => { + const env = buildNodeServiceEnvironment({ + env: { HOME: "/home/user" }, + platform: "linux", + }); + expect(env.NODE_EXTRA_CA_CERTS).toBeUndefined(); }); it("respects user-provided NODE_EXTRA_CA_CERTS for node services", () => { diff --git a/src/daemon/service-env.ts b/src/daemon/service-env.ts index 0d15120b683..15c78521348 100644 --- a/src/daemon/service-env.ts +++ b/src/daemon/service-env.ts @@ -236,12 +236,13 @@ export function buildServiceEnvironment(params: { port: number; token?: string; launchdLabel?: string; + platform?: NodeJS.Platform; }): Record { const { env, port, token, launchdLabel } = params; + const platform = params.platform ?? process.platform; const profile = env.OPENCLAW_PROFILE; const resolvedLaunchdLabel = - launchdLabel || - (process.platform === "darwin" ? resolveGatewayLaunchAgentLabel(profile) : undefined); + launchdLabel || (platform === "darwin" ? resolveGatewayLaunchAgentLabel(profile) : undefined); const systemdUnit = `${resolveGatewaySystemdServiceName(profile)}.service`; const stateDir = env.OPENCLAW_STATE_DIR; const configPath = env.OPENCLAW_CONFIG_PATH; @@ -252,7 +253,7 @@ export function buildServiceEnvironment(params: { // cannot locate the system CA bundle. Default to /etc/ssl/cert.pem so TLS verification // works correctly when running as a LaunchAgent without extra user configuration. const nodeCaCerts = - env.NODE_EXTRA_CA_CERTS ?? (process.platform === "darwin" ? "/etc/ssl/cert.pem" : undefined); + env.NODE_EXTRA_CA_CERTS ?? (platform === "darwin" ? "/etc/ssl/cert.pem" : undefined); return { HOME: env.HOME, TMPDIR: tmpDir, @@ -274,8 +275,10 @@ export function buildServiceEnvironment(params: { export function buildNodeServiceEnvironment(params: { env: Record; + platform?: NodeJS.Platform; }): Record { const { env } = params; + const platform = params.platform ?? process.platform; const stateDir = env.OPENCLAW_STATE_DIR; const configPath = env.OPENCLAW_CONFIG_PATH; const tmpDir = env.TMPDIR?.trim() || os.tmpdir(); @@ -284,7 +287,7 @@ export function buildNodeServiceEnvironment(params: { // cannot locate the system CA bundle. Default to /etc/ssl/cert.pem so TLS verification // works correctly when running as a LaunchAgent without extra user configuration. const nodeCaCerts = - env.NODE_EXTRA_CA_CERTS ?? (process.platform === "darwin" ? "/etc/ssl/cert.pem" : undefined); + env.NODE_EXTRA_CA_CERTS ?? (platform === "darwin" ? "/etc/ssl/cert.pem" : undefined); return { HOME: env.HOME, TMPDIR: tmpDir,