fix(launchd): set restrictive umask in gateway plist

This commit is contained in:
liuxiaopai-ai
2026-03-03 02:12:08 +08:00
committed by Peter Steinberger
parent 740bb77c8c
commit c9558cdcd7
3 changed files with 5 additions and 3 deletions

View File

@@ -56,6 +56,7 @@ Docs: https://docs.openclaw.ai
- Feishu/Run channel fallback: prefer `Provider` over `Surface` when inferring queued run `messageProvider` fallback (when `OriginatingChannel` is missing), preventing Feishu turns from being mislabeled as `webchat` in mixed relay metadata contexts. (#31880) Fixes #31859. Thanks @liuxiaopai-ai. - Feishu/Run channel fallback: prefer `Provider` over `Surface` when inferring queued run `messageProvider` fallback (when `OriginatingChannel` is missing), preventing Feishu turns from being mislabeled as `webchat` in mixed relay metadata contexts. (#31880) Fixes #31859. Thanks @liuxiaopai-ai.
- Sandbox/Docker setup command parsing: accept `agents.*.sandbox.docker.setupCommand` as either a string or a string array, and normalize arrays to newline-delimited shell scripts so multi-step setup commands no longer concatenate without separators. (#31953) Thanks @liuxiaopai-ai. - Sandbox/Docker setup command parsing: accept `agents.*.sandbox.docker.setupCommand` as either a string or a string array, and normalize arrays to newline-delimited shell scripts so multi-step setup commands no longer concatenate without separators. (#31953) Thanks @liuxiaopai-ai.
- Gateway/Plugin HTTP route precedence: run explicit plugin HTTP routes before the Control UI SPA catch-all so registered plugin webhook/custom paths remain reachable, while unmatched paths still fall through to Control UI handling. (#31885) Thanks @Sid-Qin. - Gateway/Plugin HTTP route precedence: run explicit plugin HTTP routes before the Control UI SPA catch-all so registered plugin webhook/custom paths remain reachable, while unmatched paths still fall through to Control UI handling. (#31885) Thanks @Sid-Qin.
- macOS/LaunchAgent security defaults: write `Umask=63` (octal `077`) into generated gateway launchd plists so post-update service reinstalls keep owner-only file permissions by default instead of falling back to system `022`. (#32022) Fixes #31905. Thanks @liuxiaopai-ai.
- Security/Node exec approvals: preserve shell/dispatch-wrapper argv semantics during approval hardening so approved wrapper commands (for example `env sh -c ...`) cannot drift into a different runtime command shape, and add regression coverage for both approval-plan generation and approved runtime execution paths. Thanks @tdjackey for reporting. - Security/Node exec approvals: preserve shell/dispatch-wrapper argv semantics during approval hardening so approved wrapper commands (for example `env sh -c ...`) cannot drift into a different runtime command shape, and add regression coverage for both approval-plan generation and approved runtime execution paths. Thanks @tdjackey for reporting.
- Sandbox/Bootstrap context boundary hardening: reject symlink/hardlink alias bootstrap seed files that resolve outside the source workspace and switch post-compaction `AGENTS.md` context reads to boundary-verified file opens, preventing host file content from being injected via workspace aliasing. Thanks @tdjackey for reporting. - Sandbox/Bootstrap context boundary hardening: reject symlink/hardlink alias bootstrap seed files that resolve outside the source workspace and switch post-compaction `AGENTS.md` context reads to boundary-verified file opens, preventing host file content from being injected via workspace aliasing. Thanks @tdjackey for reporting.
- Browser/Security output boundary hardening: replace check-then-rename output commits with root-bound fd-verified writes, unify install/skills canonical path-boundary checks, and add regression coverage for symlink-rebind race paths across browser output and shared fs-safe write flows. Thanks @tdjackey for reporting. - Browser/Security output boundary hardening: replace check-then-rename output commits with root-bound fd-verified writes, unify install/skills canonical path-boundary checks, and add regression coverage for symlink-rebind race paths across browser output and shared fs-safe write flows. Thanks @tdjackey for reporting.

View File

@@ -4,6 +4,7 @@ import fs from "node:fs/promises";
// intentional gateway restarts. Keep it low so CLI restarts and forced // intentional gateway restarts. Keep it low so CLI restarts and forced
// reinstalls do not stall for a full minute. // reinstalls do not stall for a full minute.
export const LAUNCH_AGENT_THROTTLE_INTERVAL_SECONDS = 1; export const LAUNCH_AGENT_THROTTLE_INTERVAL_SECONDS = 1;
// launchd stores plist integer values in decimal; 0o077 renders as 63 (owner-only files).
export const LAUNCH_AGENT_UMASK_DECIMAL = 0o077; export const LAUNCH_AGENT_UMASK_DECIMAL = 0o077;
const plistEscape = (value: string): string => const plistEscape = (value: string): string =>

View File

@@ -189,7 +189,7 @@ describe("launchd install", () => {
expect(plist).toContain(`<string>${tmpDir}</string>`); expect(plist).toContain(`<string>${tmpDir}</string>`);
}); });
it("writes KeepAlive=true policy", async () => { it("writes KeepAlive=true policy with restrictive umask", async () => {
const env = createDefaultLaunchdEnv(); const env = createDefaultLaunchdEnv();
await installLaunchAgent({ await installLaunchAgent({
env, env,
@@ -202,10 +202,10 @@ describe("launchd install", () => {
expect(plist).toContain("<key>KeepAlive</key>"); expect(plist).toContain("<key>KeepAlive</key>");
expect(plist).toContain("<true/>"); expect(plist).toContain("<true/>");
expect(plist).not.toContain("<key>SuccessfulExit</key>"); expect(plist).not.toContain("<key>SuccessfulExit</key>");
expect(plist).toContain("<key>ThrottleInterval</key>");
expect(plist).toContain(`<integer>${LAUNCH_AGENT_THROTTLE_INTERVAL_SECONDS}</integer>`);
expect(plist).toContain("<key>Umask</key>"); expect(plist).toContain("<key>Umask</key>");
expect(plist).toContain(`<integer>${LAUNCH_AGENT_UMASK_DECIMAL}</integer>`); expect(plist).toContain(`<integer>${LAUNCH_AGENT_UMASK_DECIMAL}</integer>`);
expect(plist).toContain("<key>ThrottleInterval</key>");
expect(plist).toContain(`<integer>${LAUNCH_AGENT_THROTTLE_INTERVAL_SECONDS}</integer>`);
}); });
it("restarts LaunchAgent with bootout-bootstrap-kickstart order", async () => { it("restarts LaunchAgent with bootout-bootstrap-kickstart order", async () => {