mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
fix(docker): persist auth profile key mount
This commit is contained in:
@@ -38,6 +38,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ${OPENCLAW_CONFIG_DIR:-${HOME:-/tmp}/.openclaw}:/home/node/.openclaw
|
- ${OPENCLAW_CONFIG_DIR:-${HOME:-/tmp}/.openclaw}:/home/node/.openclaw
|
||||||
- ${OPENCLAW_WORKSPACE_DIR:-${HOME:-/tmp}/.openclaw/workspace}:/home/node/.openclaw/workspace
|
- ${OPENCLAW_WORKSPACE_DIR:-${HOME:-/tmp}/.openclaw/workspace}:/home/node/.openclaw/workspace
|
||||||
|
- ${OPENCLAW_AUTH_PROFILE_SECRET_DIR:-${HOME:-/tmp}/.openclaw-auth-profile-secrets}:/home/node/.config/openclaw
|
||||||
## Uncomment the lines below to enable sandbox isolation
|
## Uncomment the lines below to enable sandbox isolation
|
||||||
## (agents.defaults.sandbox). Requires Docker CLI in the image
|
## (agents.defaults.sandbox). Requires Docker CLI in the image
|
||||||
## (build with --build-arg OPENCLAW_INSTALL_DOCKER_CLI=1) or use
|
## (build with --build-arg OPENCLAW_INSTALL_DOCKER_CLI=1) or use
|
||||||
@@ -112,6 +113,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ${OPENCLAW_CONFIG_DIR:-${HOME:-/tmp}/.openclaw}:/home/node/.openclaw
|
- ${OPENCLAW_CONFIG_DIR:-${HOME:-/tmp}/.openclaw}:/home/node/.openclaw
|
||||||
- ${OPENCLAW_WORKSPACE_DIR:-${HOME:-/tmp}/.openclaw/workspace}:/home/node/.openclaw/workspace
|
- ${OPENCLAW_WORKSPACE_DIR:-${HOME:-/tmp}/.openclaw/workspace}:/home/node/.openclaw/workspace
|
||||||
|
- ${OPENCLAW_AUTH_PROFILE_SECRET_DIR:-${HOME:-/tmp}/.openclaw-auth-profile-secrets}:/home/node/.config/openclaw
|
||||||
stdin_open: true
|
stdin_open: true
|
||||||
tty: true
|
tty: true
|
||||||
init: true
|
init: true
|
||||||
|
|||||||
@@ -240,9 +240,11 @@ fi
|
|||||||
|
|
||||||
OPENCLAW_CONFIG_DIR="${OPENCLAW_CONFIG_DIR:-$HOME/.openclaw}"
|
OPENCLAW_CONFIG_DIR="${OPENCLAW_CONFIG_DIR:-$HOME/.openclaw}"
|
||||||
OPENCLAW_WORKSPACE_DIR="${OPENCLAW_WORKSPACE_DIR:-$HOME/.openclaw/workspace}"
|
OPENCLAW_WORKSPACE_DIR="${OPENCLAW_WORKSPACE_DIR:-$HOME/.openclaw/workspace}"
|
||||||
|
OPENCLAW_AUTH_PROFILE_SECRET_DIR="${OPENCLAW_AUTH_PROFILE_SECRET_DIR:-$HOME/.openclaw-auth-profile-secrets}"
|
||||||
|
|
||||||
validate_mount_path_value "OPENCLAW_CONFIG_DIR" "$OPENCLAW_CONFIG_DIR"
|
validate_mount_path_value "OPENCLAW_CONFIG_DIR" "$OPENCLAW_CONFIG_DIR"
|
||||||
validate_mount_path_value "OPENCLAW_WORKSPACE_DIR" "$OPENCLAW_WORKSPACE_DIR"
|
validate_mount_path_value "OPENCLAW_WORKSPACE_DIR" "$OPENCLAW_WORKSPACE_DIR"
|
||||||
|
validate_mount_path_value "OPENCLAW_AUTH_PROFILE_SECRET_DIR" "$OPENCLAW_AUTH_PROFILE_SECRET_DIR"
|
||||||
if [[ -n "$HOME_VOLUME_NAME" ]]; then
|
if [[ -n "$HOME_VOLUME_NAME" ]]; then
|
||||||
if [[ "$HOME_VOLUME_NAME" == *"/"* ]]; then
|
if [[ "$HOME_VOLUME_NAME" == *"/"* ]]; then
|
||||||
validate_mount_path_value "OPENCLAW_HOME_VOLUME" "$HOME_VOLUME_NAME"
|
validate_mount_path_value "OPENCLAW_HOME_VOLUME" "$HOME_VOLUME_NAME"
|
||||||
@@ -270,6 +272,7 @@ fi
|
|||||||
|
|
||||||
mkdir -p "$OPENCLAW_CONFIG_DIR"
|
mkdir -p "$OPENCLAW_CONFIG_DIR"
|
||||||
mkdir -p "$OPENCLAW_WORKSPACE_DIR"
|
mkdir -p "$OPENCLAW_WORKSPACE_DIR"
|
||||||
|
mkdir -p "$OPENCLAW_AUTH_PROFILE_SECRET_DIR"
|
||||||
# Seed directory tree eagerly so bind mounts work even on Docker Desktop/Windows
|
# Seed directory tree eagerly so bind mounts work even on Docker Desktop/Windows
|
||||||
# where the container (even as root) cannot create new host subdirectories.
|
# where the container (even as root) cannot create new host subdirectories.
|
||||||
mkdir -p "$OPENCLAW_CONFIG_DIR/identity"
|
mkdir -p "$OPENCLAW_CONFIG_DIR/identity"
|
||||||
@@ -278,6 +281,7 @@ mkdir -p "$OPENCLAW_CONFIG_DIR/agents/main/sessions"
|
|||||||
|
|
||||||
export OPENCLAW_CONFIG_DIR
|
export OPENCLAW_CONFIG_DIR
|
||||||
export OPENCLAW_WORKSPACE_DIR
|
export OPENCLAW_WORKSPACE_DIR
|
||||||
|
export OPENCLAW_AUTH_PROFILE_SECRET_DIR
|
||||||
export OPENCLAW_GATEWAY_PORT="${OPENCLAW_GATEWAY_PORT:-18789}"
|
export OPENCLAW_GATEWAY_PORT="${OPENCLAW_GATEWAY_PORT:-18789}"
|
||||||
export OPENCLAW_BRIDGE_PORT="${OPENCLAW_BRIDGE_PORT:-18790}"
|
export OPENCLAW_BRIDGE_PORT="${OPENCLAW_BRIDGE_PORT:-18790}"
|
||||||
export OPENCLAW_GATEWAY_BIND="${OPENCLAW_GATEWAY_BIND:-lan}"
|
export OPENCLAW_GATEWAY_BIND="${OPENCLAW_GATEWAY_BIND:-lan}"
|
||||||
@@ -343,6 +347,7 @@ write_extra_compose() {
|
|||||||
local gateway_home_mount
|
local gateway_home_mount
|
||||||
local gateway_config_mount
|
local gateway_config_mount
|
||||||
local gateway_workspace_mount
|
local gateway_workspace_mount
|
||||||
|
local gateway_auth_profile_secret_mount
|
||||||
|
|
||||||
cat >"$EXTRA_COMPOSE_FILE" <<'YAML'
|
cat >"$EXTRA_COMPOSE_FILE" <<'YAML'
|
||||||
services:
|
services:
|
||||||
@@ -354,12 +359,15 @@ YAML
|
|||||||
gateway_home_mount="${home_volume}:/home/node"
|
gateway_home_mount="${home_volume}:/home/node"
|
||||||
gateway_config_mount="${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw"
|
gateway_config_mount="${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw"
|
||||||
gateway_workspace_mount="${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace"
|
gateway_workspace_mount="${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace"
|
||||||
|
gateway_auth_profile_secret_mount="${OPENCLAW_AUTH_PROFILE_SECRET_DIR}:/home/node/.config/openclaw"
|
||||||
validate_mount_spec "$gateway_home_mount"
|
validate_mount_spec "$gateway_home_mount"
|
||||||
validate_mount_spec "$gateway_config_mount"
|
validate_mount_spec "$gateway_config_mount"
|
||||||
validate_mount_spec "$gateway_workspace_mount"
|
validate_mount_spec "$gateway_workspace_mount"
|
||||||
|
validate_mount_spec "$gateway_auth_profile_secret_mount"
|
||||||
printf ' - %s\n' "$gateway_home_mount" >>"$EXTRA_COMPOSE_FILE"
|
printf ' - %s\n' "$gateway_home_mount" >>"$EXTRA_COMPOSE_FILE"
|
||||||
printf ' - %s\n' "$gateway_config_mount" >>"$EXTRA_COMPOSE_FILE"
|
printf ' - %s\n' "$gateway_config_mount" >>"$EXTRA_COMPOSE_FILE"
|
||||||
printf ' - %s\n' "$gateway_workspace_mount" >>"$EXTRA_COMPOSE_FILE"
|
printf ' - %s\n' "$gateway_workspace_mount" >>"$EXTRA_COMPOSE_FILE"
|
||||||
|
printf ' - %s\n' "$gateway_auth_profile_secret_mount" >>"$EXTRA_COMPOSE_FILE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for mount in "$@"; do
|
for mount in "$@"; do
|
||||||
@@ -376,6 +384,7 @@ YAML
|
|||||||
printf ' - %s\n' "$gateway_home_mount" >>"$EXTRA_COMPOSE_FILE"
|
printf ' - %s\n' "$gateway_home_mount" >>"$EXTRA_COMPOSE_FILE"
|
||||||
printf ' - %s\n' "$gateway_config_mount" >>"$EXTRA_COMPOSE_FILE"
|
printf ' - %s\n' "$gateway_config_mount" >>"$EXTRA_COMPOSE_FILE"
|
||||||
printf ' - %s\n' "$gateway_workspace_mount" >>"$EXTRA_COMPOSE_FILE"
|
printf ' - %s\n' "$gateway_workspace_mount" >>"$EXTRA_COMPOSE_FILE"
|
||||||
|
printf ' - %s\n' "$gateway_auth_profile_secret_mount" >>"$EXTRA_COMPOSE_FILE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for mount in "$@"; do
|
for mount in "$@"; do
|
||||||
@@ -473,6 +482,7 @@ upsert_env() {
|
|||||||
upsert_env "$ENV_FILE" \
|
upsert_env "$ENV_FILE" \
|
||||||
OPENCLAW_CONFIG_DIR \
|
OPENCLAW_CONFIG_DIR \
|
||||||
OPENCLAW_WORKSPACE_DIR \
|
OPENCLAW_WORKSPACE_DIR \
|
||||||
|
OPENCLAW_AUTH_PROFILE_SECRET_DIR \
|
||||||
OPENCLAW_GATEWAY_PORT \
|
OPENCLAW_GATEWAY_PORT \
|
||||||
OPENCLAW_BRIDGE_PORT \
|
OPENCLAW_BRIDGE_PORT \
|
||||||
OPENCLAW_GATEWAY_BIND \
|
OPENCLAW_GATEWAY_BIND \
|
||||||
@@ -532,6 +542,7 @@ echo "==> Fixing data-directory permissions"
|
|||||||
# (.openclaw/) inside the workspace gets chowned, not the user's project files.
|
# (.openclaw/) inside the workspace gets chowned, not the user's project files.
|
||||||
run_prestart_gateway --user root --entrypoint sh openclaw-gateway -c \
|
run_prestart_gateway --user root --entrypoint sh openclaw-gateway -c \
|
||||||
'find /home/node/.openclaw -xdev -exec chown node:node {} +; \
|
'find /home/node/.openclaw -xdev -exec chown node:node {} +; \
|
||||||
|
find /home/node/.config/openclaw -xdev -exec chown node:node {} +; \
|
||||||
[ -d /home/node/.openclaw/workspace/.openclaw ] && chown -R node:node /home/node/.openclaw/workspace/.openclaw || true'
|
[ -d /home/node/.openclaw/workspace/.openclaw ] && chown -R node:node /home/node/.openclaw/workspace/.openclaw || true'
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ function createEnv(
|
|||||||
OPENCLAW_GATEWAY_TOKEN: "test-token",
|
OPENCLAW_GATEWAY_TOKEN: "test-token",
|
||||||
OPENCLAW_CONFIG_DIR: join(sandbox.rootDir, "config"),
|
OPENCLAW_CONFIG_DIR: join(sandbox.rootDir, "config"),
|
||||||
OPENCLAW_WORKSPACE_DIR: join(sandbox.rootDir, "openclaw"),
|
OPENCLAW_WORKSPACE_DIR: join(sandbox.rootDir, "openclaw"),
|
||||||
|
OPENCLAW_AUTH_PROFILE_SECRET_DIR: join(sandbox.rootDir, "auth-profile-secrets"),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(overrides)) {
|
for (const [key, value] of Object.entries(overrides)) {
|
||||||
@@ -258,11 +259,17 @@ describe("scripts/docker/setup.sh", () => {
|
|||||||
expect(envFile).toContain("OPENCLAW_EXTRA_MOUNTS=");
|
expect(envFile).toContain("OPENCLAW_EXTRA_MOUNTS=");
|
||||||
expect(envFile).toContain("OPENCLAW_HOME_VOLUME=openclaw-home"); // pragma: allowlist secret
|
expect(envFile).toContain("OPENCLAW_HOME_VOLUME=openclaw-home"); // pragma: allowlist secret
|
||||||
expect(envFile).toContain("OPENCLAW_DISABLE_BONJOUR=");
|
expect(envFile).toContain("OPENCLAW_DISABLE_BONJOUR=");
|
||||||
|
expect(envFile).toContain(
|
||||||
|
`OPENCLAW_AUTH_PROFILE_SECRET_DIR=${join(activeSandbox.rootDir, "auth-profile-secrets")}`,
|
||||||
|
);
|
||||||
const extraCompose = await readFile(
|
const extraCompose = await readFile(
|
||||||
join(activeSandbox.rootDir, "docker-compose.extra.yml"),
|
join(activeSandbox.rootDir, "docker-compose.extra.yml"),
|
||||||
"utf8",
|
"utf8",
|
||||||
);
|
);
|
||||||
expect(extraCompose).toContain("openclaw-home:/home/node");
|
expect(extraCompose).toContain("openclaw-home:/home/node");
|
||||||
|
expect(extraCompose).toContain(
|
||||||
|
`${join(activeSandbox.rootDir, "auth-profile-secrets")}:/home/node/.config/openclaw`,
|
||||||
|
);
|
||||||
expect(extraCompose).toContain("volumes:");
|
expect(extraCompose).toContain("volumes:");
|
||||||
expect(extraCompose).toContain("openclaw-home:");
|
expect(extraCompose).toContain("openclaw-home:");
|
||||||
const log = await readDockerLog(activeSandbox);
|
const log = await readDockerLog(activeSandbox);
|
||||||
@@ -383,6 +390,27 @@ describe("scripts/docker/setup.sh", () => {
|
|||||||
expect(log).toContain("run --rm --no-deps --user root --entrypoint sh openclaw-gateway -c");
|
expect(log).toContain("run --rm --no-deps --user root --entrypoint sh openclaw-gateway -c");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("precreates auth profile secret key dir outside the mounted state dir", async () => {
|
||||||
|
const activeSandbox = requireSandbox(sandbox);
|
||||||
|
const configDir = join(activeSandbox.rootDir, "config-auth-profile-key");
|
||||||
|
const workspaceDir = join(activeSandbox.rootDir, "workspace-auth-profile-key");
|
||||||
|
const secretDir = join(activeSandbox.rootDir, "auth-profile-secret-key");
|
||||||
|
|
||||||
|
const result = runDockerSetup(activeSandbox, {
|
||||||
|
OPENCLAW_CONFIG_DIR: configDir,
|
||||||
|
OPENCLAW_WORKSPACE_DIR: workspaceDir,
|
||||||
|
OPENCLAW_AUTH_PROFILE_SECRET_DIR: secretDir,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.status).toBe(0);
|
||||||
|
const secretDirStat = await stat(secretDir);
|
||||||
|
expect(secretDirStat.isDirectory()).toBe(true);
|
||||||
|
expect(secretDir.startsWith(`${configDir}/`)).toBe(false);
|
||||||
|
|
||||||
|
const log = await readDockerLog(activeSandbox);
|
||||||
|
expect(log).toContain("find /home/node/.config/openclaw -xdev");
|
||||||
|
});
|
||||||
|
|
||||||
it("reuses existing config token when OPENCLAW_GATEWAY_TOKEN is unset", async () => {
|
it("reuses existing config token when OPENCLAW_GATEWAY_TOKEN is unset", async () => {
|
||||||
const activeSandbox = requireSandbox(sandbox);
|
const activeSandbox = requireSandbox(sandbox);
|
||||||
const { result, envFile } = await runDockerSetupWithUnsetGatewayToken(
|
const { result, envFile } = await runDockerSetupWithUnsetGatewayToken(
|
||||||
@@ -645,6 +673,15 @@ describe("scripts/docker/setup.sh", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps docker-compose auth profile secret key source durable outside state", async () => {
|
||||||
|
const compose = await readFile(join(repoRoot, "docker-compose.yml"), "utf8");
|
||||||
|
expect(
|
||||||
|
compose.split(
|
||||||
|
"${OPENCLAW_AUTH_PROFILE_SECRET_DIR:-${HOME:-/tmp}/.openclaw-auth-profile-secrets}:/home/node/.config/openclaw",
|
||||||
|
),
|
||||||
|
).toHaveLength(3);
|
||||||
|
});
|
||||||
|
|
||||||
it("keeps docker-compose optional env files aligned across services", async () => {
|
it("keeps docker-compose optional env files aligned across services", async () => {
|
||||||
const compose = await readFile(join(repoRoot, "docker-compose.yml"), "utf8");
|
const compose = await readFile(join(repoRoot, "docker-compose.yml"), "utf8");
|
||||||
expect(compose.match(/env_file:\n {6}- path: \.env\n {8}required: false/g)).toHaveLength(2);
|
expect(compose.match(/env_file:\n {6}- path: \.env\n {8}required: false/g)).toHaveLength(2);
|
||||||
|
|||||||
Reference in New Issue
Block a user