mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-11 23:10:29 +00:00
fix(docker): land #33097 from @chengzhichao-xydt
Landed from contributor PR #33097 by @chengzhichao-xydt. Co-authored-by: Zhichao Cheng <cheng.zhichao@xydigit.com>
This commit is contained in:
@@ -306,6 +306,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Nodes/system.run allow-always persistence: honor shell comment semantics during allowlist analysis so `#`-tailed payloads that never execute are not persisted as trusted follow-up commands. Thanks @tdjackey for reporting.
|
||||
- Signal/inbound attachment fan-in: forward all successfully fetched inbound attachments through `MediaPaths`/`MediaUrls`/`MediaTypes` (instead of only the first), and improve multi-attachment placeholder summaries in mention-gated pending history. (#39212) Thanks @joeykrug.
|
||||
- Nodes/system.run dispatch-wrapper boundary: keep shell-wrapper approval classification active at the depth boundary so `env` wrapper stacks cannot reach `/bin/sh -c` execution without the expected approval gate. Thanks @tdjackey for reporting.
|
||||
- Docker/token persistence on reconfigure: reuse the existing `.env` gateway token during `docker-setup.sh` reruns and align compose token env defaults, so Docker installs stop silently rotating tokens and breaking existing dashboard sessions. Landed from contributor PR #33097 by @chengzhichao-xydt. Thanks @chengzhichao-xydt.
|
||||
|
||||
## 2026.3.2
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ services:
|
||||
environment:
|
||||
HOME: /home/node
|
||||
TERM: xterm-256color
|
||||
OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN}
|
||||
OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN:-}
|
||||
OPENCLAW_ALLOW_INSECURE_PRIVATE_WS: ${OPENCLAW_ALLOW_INSECURE_PRIVATE_WS:-}
|
||||
CLAUDE_AI_SESSION_KEY: ${CLAUDE_AI_SESSION_KEY:-}
|
||||
CLAUDE_WEB_SESSION_KEY: ${CLAUDE_WEB_SESSION_KEY:-}
|
||||
@@ -59,7 +59,7 @@ services:
|
||||
environment:
|
||||
HOME: /home/node
|
||||
TERM: xterm-256color
|
||||
OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN}
|
||||
OPENCLAW_GATEWAY_TOKEN: ${OPENCLAW_GATEWAY_TOKEN:-}
|
||||
OPENCLAW_ALLOW_INSECURE_PRIVATE_WS: ${OPENCLAW_ALLOW_INSECURE_PRIVATE_WS:-}
|
||||
BROWSER: echo
|
||||
CLAUDE_AI_SESSION_KEY: ${CLAUDE_AI_SESSION_KEY:-}
|
||||
|
||||
@@ -80,6 +80,24 @@ NODE
|
||||
fi
|
||||
}
|
||||
|
||||
read_env_gateway_token() {
|
||||
local env_path="$1"
|
||||
local line=""
|
||||
local token=""
|
||||
if [[ ! -f "$env_path" ]]; then
|
||||
return 0
|
||||
fi
|
||||
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||
line="${line%$'\r'}"
|
||||
if [[ "$line" == OPENCLAW_GATEWAY_TOKEN=* ]]; then
|
||||
token="${line#OPENCLAW_GATEWAY_TOKEN=}"
|
||||
fi
|
||||
done <"$env_path"
|
||||
if [[ -n "$token" ]]; then
|
||||
printf '%s' "$token"
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_control_ui_allowed_origins() {
|
||||
if [[ "${OPENCLAW_GATEWAY_BIND}" == "loopback" ]]; then
|
||||
return 0
|
||||
@@ -219,14 +237,20 @@ if [[ -z "${OPENCLAW_GATEWAY_TOKEN:-}" ]]; then
|
||||
if [[ -n "$EXISTING_CONFIG_TOKEN" ]]; then
|
||||
OPENCLAW_GATEWAY_TOKEN="$EXISTING_CONFIG_TOKEN"
|
||||
echo "Reusing gateway token from $OPENCLAW_CONFIG_DIR/openclaw.json"
|
||||
elif command -v openssl >/dev/null 2>&1; then
|
||||
OPENCLAW_GATEWAY_TOKEN="$(openssl rand -hex 32)"
|
||||
else
|
||||
OPENCLAW_GATEWAY_TOKEN="$(python3 - <<'PY'
|
||||
DOTENV_GATEWAY_TOKEN="$(read_env_gateway_token "$ROOT_DIR/.env" || true)"
|
||||
if [[ -n "$DOTENV_GATEWAY_TOKEN" ]]; then
|
||||
OPENCLAW_GATEWAY_TOKEN="$DOTENV_GATEWAY_TOKEN"
|
||||
echo "Reusing gateway token from $ROOT_DIR/.env"
|
||||
elif command -v openssl >/dev/null 2>&1; then
|
||||
OPENCLAW_GATEWAY_TOKEN="$(openssl rand -hex 32)"
|
||||
else
|
||||
OPENCLAW_GATEWAY_TOKEN="$(python3 - <<'PY'
|
||||
import secrets
|
||||
print(secrets.token_hex(32))
|
||||
PY
|
||||
)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
export OPENCLAW_GATEWAY_TOKEN
|
||||
|
||||
@@ -250,6 +250,55 @@ describe("docker-setup.sh", () => {
|
||||
expect(envFile).toContain("OPENCLAW_GATEWAY_TOKEN=config-token-123"); // pragma: allowlist secret
|
||||
});
|
||||
|
||||
it("reuses existing .env token when OPENCLAW_GATEWAY_TOKEN and config token are unset", async () => {
|
||||
const activeSandbox = requireSandbox(sandbox);
|
||||
const configDir = join(activeSandbox.rootDir, "config-dotenv-token-reuse");
|
||||
const workspaceDir = join(activeSandbox.rootDir, "workspace-dotenv-token-reuse");
|
||||
await mkdir(configDir, { recursive: true });
|
||||
await writeFile(
|
||||
join(activeSandbox.rootDir, ".env"),
|
||||
"OPENCLAW_GATEWAY_TOKEN=dotenv-token-123\nOPENCLAW_GATEWAY_PORT=18789\n",
|
||||
);
|
||||
|
||||
const result = runDockerSetup(activeSandbox, {
|
||||
OPENCLAW_GATEWAY_TOKEN: undefined,
|
||||
OPENCLAW_CONFIG_DIR: configDir,
|
||||
OPENCLAW_WORKSPACE_DIR: workspaceDir,
|
||||
});
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
const envFile = await readFile(join(activeSandbox.rootDir, ".env"), "utf8");
|
||||
expect(envFile).toContain("OPENCLAW_GATEWAY_TOKEN=dotenv-token-123"); // pragma: allowlist secret
|
||||
expect(result.stderr).toBe("");
|
||||
});
|
||||
|
||||
it("reuses the last non-empty .env token and strips CRLF without truncating '='", async () => {
|
||||
const activeSandbox = requireSandbox(sandbox);
|
||||
const configDir = join(activeSandbox.rootDir, "config-dotenv-last-wins");
|
||||
const workspaceDir = join(activeSandbox.rootDir, "workspace-dotenv-last-wins");
|
||||
await mkdir(configDir, { recursive: true });
|
||||
await writeFile(
|
||||
join(activeSandbox.rootDir, ".env"),
|
||||
[
|
||||
"OPENCLAW_GATEWAY_TOKEN=",
|
||||
"OPENCLAW_GATEWAY_TOKEN=first-token",
|
||||
"OPENCLAW_GATEWAY_TOKEN=last=token=value\r",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
const result = runDockerSetup(activeSandbox, {
|
||||
OPENCLAW_GATEWAY_TOKEN: undefined,
|
||||
OPENCLAW_CONFIG_DIR: configDir,
|
||||
OPENCLAW_WORKSPACE_DIR: workspaceDir,
|
||||
});
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
const envFile = await readFile(join(activeSandbox.rootDir, ".env"), "utf8");
|
||||
expect(envFile).toContain("OPENCLAW_GATEWAY_TOKEN=last=token=value"); // pragma: allowlist secret
|
||||
expect(envFile).not.toContain("OPENCLAW_GATEWAY_TOKEN=first-token");
|
||||
expect(envFile).not.toContain("\r");
|
||||
});
|
||||
|
||||
it("treats OPENCLAW_SANDBOX=0 as disabled", async () => {
|
||||
const activeSandbox = requireSandbox(sandbox);
|
||||
await writeFile(activeSandbox.logPath, "");
|
||||
@@ -399,4 +448,11 @@ describe("docker-setup.sh", () => {
|
||||
expect(compose).toContain('network_mode: "service:openclaw-gateway"');
|
||||
expect(compose).toContain("depends_on:\n - openclaw-gateway");
|
||||
});
|
||||
|
||||
it("keeps docker-compose gateway token env defaults aligned across services", async () => {
|
||||
const compose = await readFile(join(repoRoot, "docker-compose.yml"), "utf8");
|
||||
expect(compose.match(/OPENCLAW_GATEWAY_TOKEN: \$\{OPENCLAW_GATEWAY_TOKEN:-\}/g)).toHaveLength(
|
||||
2,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user