mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:00:43 +00:00
fix(bonjour): suppress ciao crash when networkInterfaces() is denied
Classify ciao interface-enumeration SystemErrors from restricted sandboxes and suppress mDNS advertising instead of letting the Gateway crash.
This commit is contained in:
@@ -359,6 +359,13 @@ export async function startGatewayBonjourAdvertiser(
|
||||
|
||||
if (classification.kind === "cancellation") {
|
||||
logger.debug(`bonjour: ignoring unhandled ciao rejection: ${classification.formatted}`);
|
||||
} else if (classification.kind === "interface-enumeration-failure") {
|
||||
// Restricted sandboxes can refuse os.networkInterfaces(); mDNS cannot
|
||||
// function without it, so surface a single warning and skip recovery.
|
||||
// Recovery would just re-enter the same failing syscall.
|
||||
logger.warn(
|
||||
`bonjour: disabling mDNS — networkInterfaces() unavailable in this environment: ${classification.formatted}`,
|
||||
);
|
||||
} else {
|
||||
const label =
|
||||
classification.kind === "netmask-assertion" ? "netmask assertion" : "interface assertion";
|
||||
|
||||
@@ -100,6 +100,27 @@ describe("bonjour-ciao", () => {
|
||||
expect(ignoreCiaoUnhandledRejection(error)).toBe(true);
|
||||
});
|
||||
|
||||
it("classifies networkInterfaces SystemError failures (restricted sandboxes)", () => {
|
||||
const err = Object.assign(
|
||||
new Error("A system error occurred: uv_interface_addresses returned Unknown system error 1"),
|
||||
{ name: "SystemError" },
|
||||
);
|
||||
expect(classifyCiaoUnhandledRejection(err)).toEqual({
|
||||
kind: "interface-enumeration-failure",
|
||||
formatted:
|
||||
"SystemError: A system error occurred: uv_interface_addresses returned Unknown system error 1",
|
||||
});
|
||||
});
|
||||
|
||||
it("suppresses networkInterfaces failures wrapped in cause chains", () => {
|
||||
const inner = Object.assign(
|
||||
new Error("A system error occurred: uv_interface_addresses returned Unknown system error 1"),
|
||||
{ name: "SystemError" },
|
||||
);
|
||||
const wrapper = new Error("ciao NetworkManager init failed", { cause: inner });
|
||||
expect(ignoreCiaoUnhandledRejection(wrapper)).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps unrelated rejections visible", () => {
|
||||
expect(ignoreCiaoUnhandledRejection(new Error("boom"))).toBe(false);
|
||||
});
|
||||
|
||||
@@ -5,11 +5,16 @@ const CIAO_INTERFACE_ASSERTION_MESSAGE_RE =
|
||||
/REACHED ILLEGAL STATE!?\s+IPV4 ADDRESS CHANGE FROM (?:DEFINED TO UNDEFINED|UNDEFINED TO DEFINED)!?/u;
|
||||
const CIAO_NETMASK_ASSERTION_MESSAGE_RE =
|
||||
/IP ADDRESS VERSION MUST MATCH\.\s+NETMASK CANNOT HAVE A VERSION DIFFERENT FROM THE ADDRESS!?/u;
|
||||
// Restricted sandboxes (NemoClaw, Docker-in-Docker, k3s with locked-down policy)
|
||||
// can refuse os.networkInterfaces(), which ciao calls during NetworkManager init.
|
||||
// Node surfaces this as a SystemError mentioning the libuv syscall by name.
|
||||
const CIAO_INTERFACE_ENUMERATION_FAILURE_RE = /\bUV_INTERFACE_ADDRESSES\b/u;
|
||||
|
||||
export type CiaoProcessErrorClassification =
|
||||
| { kind: "cancellation"; formatted: string }
|
||||
| { kind: "interface-assertion"; formatted: string }
|
||||
| { kind: "netmask-assertion"; formatted: string };
|
||||
| { kind: "netmask-assertion"; formatted: string }
|
||||
| { kind: "interface-enumeration-failure"; formatted: string };
|
||||
|
||||
function collectCiaoProcessErrorCandidates(reason: unknown): unknown[] {
|
||||
const queue: unknown[] = [reason];
|
||||
@@ -64,6 +69,9 @@ export function classifyCiaoProcessError(reason: unknown): CiaoProcessErrorClass
|
||||
if (CIAO_NETMASK_ASSERTION_MESSAGE_RE.test(message)) {
|
||||
return { kind: "netmask-assertion", formatted };
|
||||
}
|
||||
if (CIAO_INTERFACE_ENUMERATION_FAILURE_RE.test(message)) {
|
||||
return { kind: "interface-enumeration-failure", formatted };
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user