mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:40:44 +00:00
fix: relax gateway service path audit
This commit is contained in:
@@ -36,6 +36,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Memory/markdown: replace CRLF managed blocks in place and collapse duplicate marker blocks without rewriting unmanaged markdown, so Dreaming and Memory Wiki files self-heal from repeated generated sections. Fixes #75491; supersedes #75495, #75810, and #76008. Thanks @asaenokkostya-coder, @ottodeng, @everettjf, and @lrg913427-dot.
|
||||
- Agents/tools: return critical tool-loop circuit-breaker stops as blocked tool results instead of thrown tool failures, so models see the guardrail and stop retrying the same call. Thanks @rayraiser.
|
||||
- Model commands: clarify direct and inline `/model` acknowledgements for non-default selections as session-scoped. Thanks @addu2612.
|
||||
- Doctor/gateway: stop warning that non-existent, unconfigured user-bin directories are required in the Gateway service PATH. Fixes #76017. Thanks @xiphis.
|
||||
- TUI/chat: skip full provider model normalization during context-window warmup while preserving provider-owned context metadata, avoiding cold-start stalls with large model registries. Thanks @547895019.
|
||||
- Memory Wiki: accept relative Markdown links that include the `.md` suffix during broken-wikilink validation, avoiding false positives for native render-mode links. Thanks @Kenneth8128.
|
||||
- OpenAI Codex: show the device-pairing code in the interactive SSH/headless prompt while keeping the short-lived code out of persistent runtime logs. Fixes #74212. Thanks @da22le123.
|
||||
|
||||
@@ -473,7 +473,7 @@ That stages grounded durable candidates into the short-term dreaming store while
|
||||
<Accordion title="17. Gateway runtime best practices">
|
||||
Doctor warns when the gateway service runs on Bun or a version-managed Node path (`nvm`, `fnm`, `volta`, `asdf`, etc.). WhatsApp + Telegram channels require Node, and version-manager paths can break after upgrades because the service does not load your shell init. Doctor offers to migrate to a system Node install when available (Homebrew/apt/choco).
|
||||
|
||||
Newly installed or repaired services keep explicit environment roots (`NVM_DIR`, `FNM_DIR`, `VOLTA_HOME`, `ASDF_DATA_DIR`, `BUN_INSTALL`, `PNPM_HOME`) and stable user-bin directories, but guessed version-manager fallback directories are only written to the service PATH when those directories exist on disk. This keeps the generated supervisor PATH aligned with the same minimal-PATH audit doctor runs later.
|
||||
Newly installed or repaired services keep explicit environment roots (`NVM_DIR`, `FNM_DIR`, `VOLTA_HOME`, `ASDF_DATA_DIR`, `BUN_INSTALL`, `PNPM_HOME`) and stable user-bin directories, but guessed version-manager fallback directories are only written to the service PATH when those directories exist on disk. The audit accepts existing stable user-bin directories and explicit environment roots; it does not warn that missing, unconfigured `$HOME/.npm-global/bin`, `$HOME/bin`, or `$HOME/.nix-profile/bin` entries are required.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="18. Config write + wizard metadata">
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
auditGatewayServiceConfig,
|
||||
@@ -120,6 +123,50 @@ describe("auditGatewayServiceConfig", () => {
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("does not require missing unconfigured user-bin defaults in gateway service PATH", async () => {
|
||||
const home = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-service-audit-home-"));
|
||||
try {
|
||||
const localBin = path.join(home, ".local/bin");
|
||||
await fs.mkdir(localBin, { recursive: true });
|
||||
const servicePath = [
|
||||
localBin,
|
||||
"/opt/homebrew/bin",
|
||||
"/usr/local/bin",
|
||||
"/usr/bin",
|
||||
"/bin",
|
||||
].join(":");
|
||||
|
||||
const audit = await auditGatewayServiceConfig({
|
||||
env: { HOME: home },
|
||||
platform: "darwin",
|
||||
command: {
|
||||
programArguments: ["/usr/bin/node", "gateway"],
|
||||
environment: { PATH: servicePath },
|
||||
},
|
||||
});
|
||||
|
||||
expect(hasIssue(audit, SERVICE_AUDIT_CODES.gatewayPathMissingDirs)).toBe(false);
|
||||
} finally {
|
||||
await fs.rm(home, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("still requires explicit env-configured tool roots in gateway service PATH", async () => {
|
||||
const audit = await auditGatewayServiceConfig({
|
||||
env: { HOME: "/tmp/openclaw-testuser", PNPM_HOME: "/opt/pnpm" },
|
||||
platform: "linux",
|
||||
command: {
|
||||
programArguments: ["/usr/bin/node", "gateway"],
|
||||
environment: { PATH: "/usr/local/bin:/usr/bin:/bin" },
|
||||
},
|
||||
});
|
||||
|
||||
const issue = audit.issues.find(
|
||||
(entry) => entry.code === SERVICE_AUDIT_CODES.gatewayPathMissingDirs,
|
||||
);
|
||||
expect(issue?.message).toContain("/opt/pnpm");
|
||||
});
|
||||
|
||||
it("accepts Linux fnm aliases/default without requiring the legacy current symlink", async () => {
|
||||
const env = {
|
||||
HOME: "/tmp/openclaw-testuser",
|
||||
|
||||
@@ -433,7 +433,11 @@ function auditGatewayServicePath(
|
||||
return;
|
||||
}
|
||||
|
||||
const expected = getMinimalServicePathPartsFromEnv({ platform, env });
|
||||
const expected = getMinimalServicePathPartsFromEnv({
|
||||
platform,
|
||||
env,
|
||||
includeMissingUserBinDefaults: false,
|
||||
});
|
||||
const parts = servicePath
|
||||
.split(getPathModule(platform).delimiter)
|
||||
.map((entry) => entry.trim())
|
||||
|
||||
@@ -231,6 +231,20 @@ describe("getMinimalServicePathParts - Linux user directories", () => {
|
||||
expect(result).not.toContain("/Users/testuser/.local/share/pnpm");
|
||||
});
|
||||
|
||||
it("can omit missing stable user-bin defaults for service PATH audits", () => {
|
||||
const result = getMinimalServicePathPartsFromEnv({
|
||||
platform: "darwin",
|
||||
env: { HOME: "/Users/testuser" },
|
||||
existsSync: (candidate) => candidate === "/Users/testuser/.local/bin",
|
||||
includeMissingUserBinDefaults: false,
|
||||
});
|
||||
|
||||
expect(result).toContain("/Users/testuser/.local/bin");
|
||||
expect(result).not.toContain("/Users/testuser/.npm-global/bin");
|
||||
expect(result).not.toContain("/Users/testuser/bin");
|
||||
expect(result).not.toContain("/Users/testuser/.nix-profile/bin");
|
||||
});
|
||||
|
||||
it("keeps env-configured roots when fallback directories are missing", () => {
|
||||
const result = getMinimalServicePathPartsFromEnv({
|
||||
platform: "linux",
|
||||
|
||||
@@ -32,6 +32,7 @@ type MinimalServicePathOptions = {
|
||||
cwd?: string;
|
||||
env?: Record<string, string | undefined>;
|
||||
existsSync?: (candidate: string) => boolean;
|
||||
includeMissingUserBinDefaults?: boolean;
|
||||
};
|
||||
|
||||
type BuildServicePathOptions = MinimalServicePathOptions & {
|
||||
@@ -168,10 +169,14 @@ function addCommonUserBinDirs(
|
||||
dirs: string[],
|
||||
home: string,
|
||||
existsSync: (candidate: string) => boolean,
|
||||
includeMissingDefaults: boolean,
|
||||
): void {
|
||||
dirs.push(`${home}/.local/bin`);
|
||||
dirs.push(`${home}/.npm-global/bin`);
|
||||
dirs.push(`${home}/bin`);
|
||||
const addDefault = includeMissingDefaults
|
||||
? (candidate: string) => dirs.push(candidate)
|
||||
: (candidate: string) => addExistingDir(dirs, candidate, existsSync);
|
||||
addDefault(`${home}/.local/bin`);
|
||||
addDefault(`${home}/.npm-global/bin`);
|
||||
addDefault(`${home}/bin`);
|
||||
addExistingDir(dirs, `${home}/.volta/bin`, existsSync);
|
||||
addExistingDir(dirs, `${home}/.asdf/shims`, existsSync);
|
||||
addExistingDir(dirs, `${home}/.bun/bin`, existsSync);
|
||||
@@ -196,6 +201,8 @@ function addNixProfileBinDirs(
|
||||
home: string,
|
||||
env: Record<string, string | undefined> | undefined,
|
||||
options: Pick<MinimalServicePathOptions, "cwd" | "home">,
|
||||
includeMissingDefault: boolean,
|
||||
existsSync: (candidate: string) => boolean,
|
||||
): void {
|
||||
const nixProfiles = env?.NIX_PROFILES?.trim();
|
||||
if (nixProfiles) {
|
||||
@@ -203,7 +210,12 @@ function addNixProfileBinDirs(
|
||||
addEnvConfiguredBinDir(dirs, appendSubdir(profile, "bin"), options);
|
||||
}
|
||||
} else {
|
||||
dirs.push(`${home}/.nix-profile/bin`);
|
||||
const defaultProfileBin = `${home}/.nix-profile/bin`;
|
||||
if (includeMissingDefault) {
|
||||
dirs.push(defaultProfileBin);
|
||||
} else {
|
||||
addExistingDir(dirs, defaultProfileBin, existsSync);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +241,7 @@ function resolveDarwinUserBinDirs(
|
||||
home: string | undefined,
|
||||
env?: Record<string, string | undefined>,
|
||||
existsSync: (candidate: string) => boolean = fs.existsSync,
|
||||
options: Pick<MinimalServicePathOptions, "cwd" | "home"> = {},
|
||||
options: Pick<MinimalServicePathOptions, "cwd" | "home" | "includeMissingUserBinDefaults"> = {},
|
||||
): string[] {
|
||||
if (!home) {
|
||||
return [];
|
||||
@@ -237,6 +249,7 @@ function resolveDarwinUserBinDirs(
|
||||
|
||||
const dirs: string[] = [];
|
||||
const pathOptions = { ...options, home };
|
||||
const includeMissingUserBinDefaults = options.includeMissingUserBinDefaults ?? true;
|
||||
|
||||
// Env-configured bin roots (override defaults when present).
|
||||
// Note: FNM_DIR on macOS defaults to ~/Library/Application Support/fnm
|
||||
@@ -250,10 +263,10 @@ function resolveDarwinUserBinDirs(
|
||||
// pnpm: binary is directly in PNPM_HOME (not in bin subdirectory)
|
||||
|
||||
// Common user bin directories
|
||||
addCommonUserBinDirs(dirs, home, existsSync);
|
||||
addCommonUserBinDirs(dirs, home, existsSync, includeMissingUserBinDefaults);
|
||||
|
||||
// Nix Home Manager (cross-platform)
|
||||
addNixProfileBinDirs(dirs, home, env, pathOptions);
|
||||
addNixProfileBinDirs(dirs, home, env, pathOptions, includeMissingUserBinDefaults, existsSync);
|
||||
|
||||
// Node version managers - macOS specific paths
|
||||
// nvm: no stable default path, depends on user's shell configuration
|
||||
@@ -275,7 +288,7 @@ function resolveLinuxUserBinDirs(
|
||||
home: string | undefined,
|
||||
env?: Record<string, string | undefined>,
|
||||
existsSync: (candidate: string) => boolean = fs.existsSync,
|
||||
options: Pick<MinimalServicePathOptions, "cwd" | "home"> = {},
|
||||
options: Pick<MinimalServicePathOptions, "cwd" | "home" | "includeMissingUserBinDefaults"> = {},
|
||||
): string[] {
|
||||
if (!home) {
|
||||
return [];
|
||||
@@ -283,6 +296,7 @@ function resolveLinuxUserBinDirs(
|
||||
|
||||
const dirs: string[] = [];
|
||||
const pathOptions = { ...options, home };
|
||||
const includeMissingUserBinDefaults = options.includeMissingUserBinDefaults ?? true;
|
||||
|
||||
// Env-configured bin roots (override defaults when present).
|
||||
addCommonEnvConfiguredBinDirs(dirs, env, pathOptions);
|
||||
@@ -291,10 +305,10 @@ function resolveLinuxUserBinDirs(
|
||||
addEnvConfiguredBinDir(dirs, appendSubdir(env?.FNM_DIR, "current/bin"), pathOptions);
|
||||
|
||||
// Common user bin directories
|
||||
addCommonUserBinDirs(dirs, home, existsSync);
|
||||
addCommonUserBinDirs(dirs, home, existsSync, includeMissingUserBinDefaults);
|
||||
|
||||
// Nix Home Manager (cross-platform)
|
||||
addNixProfileBinDirs(dirs, home, env, pathOptions);
|
||||
addNixProfileBinDirs(dirs, home, env, pathOptions, includeMissingUserBinDefaults, existsSync);
|
||||
|
||||
// Node version managers
|
||||
addExistingDir(dirs, `${home}/.nvm/current/bin`, existsSync); // nvm with current symlink
|
||||
|
||||
Reference in New Issue
Block a user