mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 04:50:44 +00:00
test(sandbox): cover registry migration
This commit is contained in:
@@ -17,6 +17,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Plugins/update: on the beta OpenClaw update channel, default-line npm and ClawHub plugin updates try `@beta` first and fall back to default/latest when no plugin beta release exists.
|
||||
- Channels/WhatsApp: support explicit WhatsApp Channel/Newsletter `@newsletter` outbound message targets with channel session metadata instead of DM routing. Fixes #13417; carries forward the narrow outbound target idea from #13424. Thanks @vincentkoc and @agentz-manfred.
|
||||
- Exec approvals: add a tree-sitter-backed shell command explainer for future approval and command-review surfaces. (#75004) Thanks @jesse-merhi.
|
||||
- Agents/sandbox: store sandbox container and browser registry entries as per-runtime shard files, reducing unrelated session lock contention while `openclaw doctor --fix` migrates legacy monolithic registry files. (#74831) Thanks @luckylhb90.
|
||||
|
||||
### Fixes
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ Notes:
|
||||
- Doctor warns when Codex-mode agents are configured and personal Codex CLI assets exist in the operator's Codex home. Local Codex app-server launches use isolated per-agent homes, so use `openclaw migrate codex --dry-run` to inventory assets that should be promoted deliberately.
|
||||
- Doctor warns when skills allowed for the default agent are unavailable in the current runtime environment because bins, env vars, config, or OS requirements are missing. `doctor --fix` can disable those unavailable skills with `skills.entries.<skill>.enabled=false`; install/configure the missing requirement instead when you want to keep the skill active.
|
||||
- If sandbox mode is enabled but Docker is unavailable, doctor reports a high-signal warning with remediation (`install Docker` or `openclaw config set agents.defaults.sandbox.mode off`).
|
||||
- If legacy sandbox registry files (`~/.openclaw/sandbox/containers.json` or `~/.openclaw/sandbox/browsers.json`) are present, doctor reports them; `openclaw doctor --fix` migrates valid entries into sharded registry directories and quarantines invalid legacy files.
|
||||
- If `gateway.auth.token`/`gateway.auth.password` are SecretRef-managed and unavailable in the current command path, doctor reports a read-only warning and does not write plaintext fallback credentials.
|
||||
- If channel SecretRef inspection fails in a fix path, doctor continues and reports a warning instead of exiting early.
|
||||
- After state-directory migrations, doctor warns when enabled default Telegram or Discord accounts depend on env fallback and `TELEGRAM_BOT_TOKEN` or `DISCORD_BOT_TOKEN` is unavailable to the doctor process.
|
||||
|
||||
@@ -164,6 +164,15 @@ Use `openclaw sandbox recreate` to force removal of old runtimes. They are recre
|
||||
Prefer `openclaw sandbox recreate` over manual backend-specific cleanup. It uses the Gateway's runtime registry and avoids mismatches when scope or session keys change.
|
||||
</Tip>
|
||||
|
||||
## Registry migration
|
||||
|
||||
OpenClaw stores sandbox runtime metadata as one JSON shard per container/browser entry under the sandbox state directory. Older installs may still have monolithic legacy files:
|
||||
|
||||
- `~/.openclaw/sandbox/containers.json`
|
||||
- `~/.openclaw/sandbox/browsers.json`
|
||||
|
||||
Regular sandbox runtime reads do not rewrite those files. Run `openclaw doctor --fix` to migrate valid legacy entries into the sharded registry directories. Invalid legacy files are quarantined so one bad old registry cannot hide current runtime entries.
|
||||
|
||||
## Configuration
|
||||
|
||||
Sandbox settings live in `~/.openclaw/openclaw.json` under `agents.defaults.sandbox` (per-agent overrides go in `agents.list[].sandbox`):
|
||||
|
||||
@@ -172,6 +172,22 @@ async function seedContainerRegistry(entries: SandboxRegistryEntry[]) {
|
||||
await fs.writeFile(SANDBOX_REGISTRY_PATH, `${JSON.stringify({ entries }, null, 2)}\n`, "utf-8");
|
||||
}
|
||||
|
||||
async function seedBrowserRegistry(entries: SandboxBrowserRegistryEntry[]) {
|
||||
await fs.writeFile(
|
||||
SANDBOX_BROWSER_REGISTRY_PATH,
|
||||
`${JSON.stringify({ entries }, null, 2)}\n`,
|
||||
"utf-8",
|
||||
);
|
||||
}
|
||||
|
||||
async function seedStaleLock(lockPath: string) {
|
||||
await fs.writeFile(
|
||||
lockPath,
|
||||
`${JSON.stringify({ pid: 999_999_999, createdAt: "2000-01-01T00:00:00.000Z" })}\n`,
|
||||
"utf-8",
|
||||
);
|
||||
}
|
||||
|
||||
describe("registry race safety", () => {
|
||||
it("does not migrate legacy registry files from runtime reads", async () => {
|
||||
await seedContainerRegistry([containerEntry({ containerName: "legacy-container" })]);
|
||||
@@ -204,6 +220,60 @@ describe("registry race safety", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("migrates legacy container and browser registry files after explicit repair", async () => {
|
||||
await seedContainerRegistry([
|
||||
containerEntry({
|
||||
containerName: "legacy-container",
|
||||
sessionKey: "agent:legacy",
|
||||
lastUsedAtMs: 7,
|
||||
configHash: "legacy-container-hash",
|
||||
}),
|
||||
]);
|
||||
await seedBrowserRegistry([
|
||||
browserEntry({
|
||||
containerName: "legacy-browser",
|
||||
sessionKey: "agent:legacy",
|
||||
cdpPort: 9333,
|
||||
noVncPort: 6081,
|
||||
configHash: "legacy-browser-hash",
|
||||
}),
|
||||
]);
|
||||
await seedStaleLock(`${SANDBOX_REGISTRY_PATH}.lock`);
|
||||
await seedStaleLock(`${SANDBOX_BROWSER_REGISTRY_PATH}.lock`);
|
||||
|
||||
await expect(migrateLegacySandboxRegistryFiles()).resolves.toEqual([
|
||||
expect.objectContaining({ kind: "containers", status: "migrated", entries: 1 }),
|
||||
expect.objectContaining({ kind: "browsers", status: "migrated", entries: 1 }),
|
||||
]);
|
||||
|
||||
await expect(fs.access(SANDBOX_REGISTRY_PATH)).rejects.toThrow();
|
||||
await expect(fs.access(SANDBOX_BROWSER_REGISTRY_PATH)).rejects.toThrow();
|
||||
await expect(fs.access(`${SANDBOX_REGISTRY_PATH}.lock`)).rejects.toThrow();
|
||||
await expect(fs.access(`${SANDBOX_BROWSER_REGISTRY_PATH}.lock`)).rejects.toThrow();
|
||||
await expect(readRegistry()).resolves.toEqual({
|
||||
entries: [
|
||||
expect.objectContaining({
|
||||
containerName: "legacy-container",
|
||||
backendId: "docker",
|
||||
runtimeLabel: "legacy-container",
|
||||
sessionKey: "agent:legacy",
|
||||
configHash: "legacy-container-hash",
|
||||
}),
|
||||
],
|
||||
});
|
||||
await expect(readBrowserRegistry()).resolves.toEqual({
|
||||
entries: [
|
||||
expect.objectContaining({
|
||||
containerName: "legacy-browser",
|
||||
sessionKey: "agent:legacy",
|
||||
cdpPort: 9333,
|
||||
noVncPort: 6081,
|
||||
configHash: "legacy-browser-hash",
|
||||
}),
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("does not overwrite newer sharded entries during legacy migration", async () => {
|
||||
await updateRegistry(
|
||||
containerEntry({
|
||||
|
||||
Reference in New Issue
Block a user