mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-09 07:13:58 +00:00
fix(macos): preserve launchd Node gateway in PortGuardian (#100867)
* fix(macos): preserve launchd Node gateway in PortGuardian Co-authored-by: lsr911 <18230762+lsr911@users.noreply.github.com> * fix(macos): tighten PortGuardian gateway matcher --------- Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com> Co-authored-by: lsr911 <18230762+lsr911@users.noreply.github.com>
This commit is contained in:
@@ -534,6 +534,7 @@ actor PortGuardian {
|
||||
{
|
||||
return true
|
||||
}
|
||||
if self.isNodeOpenClawGatewayCommand(full) { return true }
|
||||
// If args are unavailable, treat a CLI listener as expected.
|
||||
if cmd.contains("openclaw"), full == cmd { return true }
|
||||
return false
|
||||
@@ -542,6 +543,30 @@ actor PortGuardian {
|
||||
}
|
||||
}
|
||||
|
||||
private static func isNodeOpenClawGatewayCommand(_ fullCommand: String) -> Bool {
|
||||
let tokens = fullCommand
|
||||
.split(whereSeparator: \.isWhitespace)
|
||||
.map { self.unquoteCommandToken(String($0)) }
|
||||
guard tokens.count >= 3 else { return false }
|
||||
guard URL(fileURLWithPath: tokens[0]).lastPathComponent.lowercased() == "node" else {
|
||||
return false
|
||||
}
|
||||
return self.isOpenClawDistEntrypointToken(tokens[1])
|
||||
&& tokens[2].lowercased() == "gateway"
|
||||
}
|
||||
|
||||
private static func isOpenClawDistEntrypointToken(_ token: String) -> Bool {
|
||||
let normalized = token.replacingOccurrences(of: "\\", with: "/").lowercased()
|
||||
guard normalized.hasSuffix("/dist/index.js") else { return false }
|
||||
return normalized
|
||||
.split(separator: "/", omittingEmptySubsequences: true)
|
||||
.contains("openclaw")
|
||||
}
|
||||
|
||||
private static func unquoteCommandToken(_ token: String) -> String {
|
||||
token.trimmingCharacters(in: CharacterSet(charactersIn: "\"'"))
|
||||
}
|
||||
|
||||
private func probeGatewayHealthIfNeeded(
|
||||
port: Int,
|
||||
mode: AppState.ConnectionMode,
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import OpenClaw
|
||||
|
||||
struct PortGuardianIsExpectedTests {
|
||||
@Test func `local mode preserves launchd node dist gateway command`() {
|
||||
let fullCommand = """
|
||||
/opt/homebrew/bin/node /opt/homebrew/lib/node_modules/openclaw/dist/index.js gateway --port 18789 --bind loopback
|
||||
"""
|
||||
|
||||
#expect(PortGuardian._testIsExpected(
|
||||
command: "node",
|
||||
fullCommand: fullCommand,
|
||||
port: 18789,
|
||||
mode: .local))
|
||||
}
|
||||
|
||||
@Test func `local mode preserves git checkout node dist gateway command`() {
|
||||
let fullCommand = """
|
||||
/usr/local/bin/node /Users/dev/Projects/openclaw/dist/index.js gateway --port 18789
|
||||
"""
|
||||
|
||||
#expect(PortGuardian._testIsExpected(
|
||||
command: "node",
|
||||
fullCommand: fullCommand,
|
||||
port: 18789,
|
||||
mode: .local))
|
||||
}
|
||||
|
||||
@Test func `local mode rejects similarly named node project`() {
|
||||
#expect(!PortGuardian._testIsExpected(
|
||||
command: "node",
|
||||
fullCommand: "/usr/local/bin/node /tmp/openclaw-tools/dist/index.js gateway --port 18789",
|
||||
port: 18789,
|
||||
mode: .local))
|
||||
}
|
||||
|
||||
@Test func `local mode rejects gateway appearing after another node argument`() {
|
||||
#expect(!PortGuardian._testIsExpected(
|
||||
command: "node",
|
||||
fullCommand: "/usr/local/bin/node --inspect /tmp/openclaw/dist/index.js gateway --port 18789",
|
||||
port: 18789,
|
||||
mode: .local))
|
||||
}
|
||||
|
||||
@Test func `local mode rejects node dist entrypoint without gateway subcommand`() {
|
||||
#expect(!PortGuardian._testIsExpected(
|
||||
command: "node",
|
||||
fullCommand: "/opt/homebrew/bin/node /opt/homebrew/lib/node_modules/openclaw/dist/index.js doctor",
|
||||
port: 18789,
|
||||
mode: .local))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user