fix(bonjour): auto-disable advertising in containers

This commit is contained in:
Peter Steinberger
2026-04-26 23:59:38 +01:00
parent 89ab39ca64
commit 989cfd1e33
2 changed files with 81 additions and 2 deletions

View File

@@ -1,3 +1,4 @@
import fs from "node:fs";
import os from "node:os";
import { afterEach, describe, expect, it, vi } from "vitest";
@@ -207,6 +208,38 @@ describe("gateway bonjour advertiser", () => {
await expect(started.stop()).resolves.toBeUndefined();
});
it("auto-disables Bonjour in detected containers", async () => {
enableAdvertiserUnitMode();
vi.spyOn(fs, "existsSync").mockImplementation((filePath) => String(filePath) === "/.dockerenv");
const started = await startAdvertiser({
gatewayPort: 18789,
sshPort: 2222,
});
expect(createService).not.toHaveBeenCalled();
await expect(started.stop()).resolves.toBeUndefined();
});
it("honors explicit Bonjour opt-in inside detected containers", async () => {
enableAdvertiserUnitMode();
process.env.OPENCLAW_DISABLE_BONJOUR = "0";
vi.spyOn(fs, "existsSync").mockImplementation((filePath) => String(filePath) === "/.dockerenv");
const destroy = vi.fn().mockResolvedValue(undefined);
const advertise = vi.fn().mockResolvedValue(undefined);
mockCiaoService({ advertise, destroy });
const started = await startAdvertiser({
gatewayPort: 18789,
sshPort: 2222,
});
expect(createService).toHaveBeenCalledTimes(1);
await started.stop();
});
it("attaches conflict listeners for services", async () => {
enableAdvertiserUnitMode();

View File

@@ -1,3 +1,4 @@
import fs from "node:fs";
import type { PluginLogger } from "openclaw/plugin-sdk/plugin-entry";
import { isTruthyEnvValue } from "openclaw/plugin-sdk/runtime-env";
import { classifyCiaoProcessError, type CiaoProcessErrorClassification } from "./ciao.js";
@@ -89,16 +90,61 @@ async function loadCiaoModule(): Promise<CiaoModule> {
return ciaoModulePromise;
}
function isDisabledByEnv() {
if (isTruthyEnvValue(process.env.OPENCLAW_DISABLE_BONJOUR)) {
function readBonjourDisableOverride(): boolean | null {
const raw = process.env.OPENCLAW_DISABLE_BONJOUR;
const normalized = raw?.trim().toLowerCase();
if (!normalized) {
return null;
}
if (isTruthyEnvValue(raw)) {
return true;
}
switch (normalized) {
case "0":
case "false":
case "no":
case "off":
return false;
default:
return null;
}
}
function isContainerEnvironment() {
for (const sentinelPath of ["/.dockerenv", "/run/.containerenv", "/var/run/.containerenv"]) {
try {
if (fs.existsSync(sentinelPath)) {
return true;
}
} catch {
// ignore
}
}
try {
const cgroup = fs.readFileSync("/proc/1/cgroup", "utf8");
return /\/docker\/|cri-containerd-[0-9a-f]|containerd\/[0-9a-f]{64}|\/kubepods[/.]|\blxc\b/u.test(
cgroup,
);
} catch {
return false;
}
}
function isDisabledByEnv() {
if (process.env.NODE_ENV === "test") {
return true;
}
if (process.env.VITEST) {
return true;
}
const envOverride = readBonjourDisableOverride();
if (envOverride !== null) {
return envOverride;
}
if (isContainerEnvironment()) {
return true;
}
return false;
}