mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(macos): stop runtime config-health sidecar access (#99039)
Summary: - The PR removes macOS runtime reads and writes of `logs/config-health.json`, keeps config-health observation in process memory, and adds Swift tests for ignoring and not recreating the retired sidecar. - PR surface: Other +22. Total +22 across 2 files. - Reproducibility: yes. Current main still writes `logs/config-health.json` from the macOS config observation path, and the PR body includes before/after terminal output for that same Swift path. Automerge notes: - No ClawSweeper repair was needed after automerge opt-in. Validation: - ClawSweeper review passed for head8cbc4e10d3. - Required merge gates passed before the squash merge. Prepared head SHA:8cbc4e10d3Review: https://github.com/openclaw/openclaw/pull/99039#issuecomment-4864550335 Co-authored-by: momothemage <niuzhengnan@163.com> Approved-by: momothemage
This commit is contained in:
@@ -5,8 +5,8 @@ import OpenClawProtocol
|
||||
enum OpenClawConfigFile {
|
||||
private static let logger = Logger(subsystem: "ai.openclaw", category: "config")
|
||||
private static let configAuditFileName = "config-audit.jsonl"
|
||||
private static let configHealthFileName = "config-health.json"
|
||||
private static let fileLock = NSRecursiveLock()
|
||||
private nonisolated(unsafe) static var configHealthState: [String: Any] = [:]
|
||||
|
||||
private static func withFileLock<T>(_ body: () throws -> T) rethrows -> T {
|
||||
self.fileLock.lock()
|
||||
@@ -477,39 +477,6 @@ enum OpenClawConfigFile {
|
||||
.appendingPathComponent(self.configAuditFileName, isDirectory: false)
|
||||
}
|
||||
|
||||
private static func configHealthStateURL() -> URL {
|
||||
self.stateDirURL()
|
||||
.appendingPathComponent("logs", isDirectory: true)
|
||||
.appendingPathComponent(self.configHealthFileName, isDirectory: false)
|
||||
}
|
||||
|
||||
private static func readConfigHealthState() -> [String: Any] {
|
||||
let url = self.configHealthStateURL()
|
||||
guard let data = try? Data(contentsOf: url),
|
||||
let root = try? JSONSerialization.jsonObject(with: data) as? [String: Any]
|
||||
else {
|
||||
return [:]
|
||||
}
|
||||
return root
|
||||
}
|
||||
|
||||
private static func writeConfigHealthState(_ root: [String: Any]) {
|
||||
guard JSONSerialization.isValidJSONObject(root),
|
||||
let data = try? JSONSerialization.data(withJSONObject: root, options: [.prettyPrinted, .sortedKeys])
|
||||
else {
|
||||
return
|
||||
}
|
||||
let url = self.configHealthStateURL()
|
||||
do {
|
||||
try FileManager().createDirectory(
|
||||
at: url.deletingLastPathComponent(),
|
||||
withIntermediateDirectories: true)
|
||||
try data.write(to: url, options: [.atomic])
|
||||
} catch {
|
||||
// best-effort
|
||||
}
|
||||
}
|
||||
|
||||
private static func configHealthEntry(state: [String: Any], configPath: String) -> [String: Any] {
|
||||
let entries = state["entries"] as? [String: Any]
|
||||
return entries?[configPath] as? [String: Any] ?? [:]
|
||||
@@ -672,7 +639,7 @@ enum OpenClawConfigFile {
|
||||
private static func observeConfigRead(data: Data, root: [String: Any]?, configURL: URL, valid: Bool) {
|
||||
let observedAt = ISO8601DateFormatter().string(from: Date())
|
||||
let current = self.configFingerprint(data: data, root: root, configURL: configURL, observedAt: observedAt)
|
||||
var state = self.readConfigHealthState()
|
||||
var state = self.configHealthState
|
||||
let entry = self.configHealthEntry(state: state, configPath: configURL.path)
|
||||
let lastKnownGood = entry["lastKnownGood"] as? [String: Any]
|
||||
let suspicious = self.observeSuspiciousReasons(
|
||||
@@ -688,7 +655,7 @@ enum OpenClawConfigFile {
|
||||
]
|
||||
if !self.sameFingerprint(lastKnownGood, current) || entry["lastObservedSuspiciousSignature"] != nil {
|
||||
state = self.setConfigHealthEntry(state: state, configPath: configURL.path, entry: nextEntry)
|
||||
self.writeConfigHealthState(state)
|
||||
self.configHealthState = state
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -750,7 +717,7 @@ enum OpenClawConfigFile {
|
||||
var nextEntry = entry
|
||||
nextEntry["lastObservedSuspiciousSignature"] = signature
|
||||
state = self.setConfigHealthEntry(state: state, configPath: configURL.path, entry: nextEntry)
|
||||
self.writeConfigHealthState(state)
|
||||
self.configHealthState = state
|
||||
}
|
||||
|
||||
private static func appendConfigWriteAudit(_ fields: [String: Any]) {
|
||||
|
||||
@@ -266,6 +266,58 @@ struct OpenClawConfigFileTests {
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
@Test
|
||||
func `load dict ignores legacy config health sidecar`() async throws {
|
||||
let stateDir = FileManager().temporaryDirectory
|
||||
.appendingPathComponent("openclaw-state-\(UUID().uuidString)", isDirectory: true)
|
||||
let configPath = stateDir.appendingPathComponent("openclaw.json")
|
||||
let auditPath = stateDir.appendingPathComponent("logs/config-audit.jsonl")
|
||||
let configHealthPath = stateDir.appendingPathComponent("logs/config-health.json")
|
||||
|
||||
defer { try? FileManager().removeItem(at: stateDir) }
|
||||
|
||||
try FileManager().createDirectory(
|
||||
at: configHealthPath.deletingLastPathComponent(),
|
||||
withIntermediateDirectories: true)
|
||||
let legacyHealth = """
|
||||
{
|
||||
"entries": {
|
||||
"\(configPath.path)": {
|
||||
"lastKnownGood": {
|
||||
"bytes": 4096,
|
||||
"gatewayMode": "local",
|
||||
"hasMeta": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
try legacyHealth.write(to: configHealthPath, atomically: true, encoding: .utf8)
|
||||
let updateOnlyConfig = """
|
||||
{
|
||||
"update": {
|
||||
"channel": "beta"
|
||||
}
|
||||
}
|
||||
"""
|
||||
try updateOnlyConfig.write(to: configPath, atomically: true, encoding: .utf8)
|
||||
|
||||
try await TestIsolation.withEnvValues([
|
||||
"OPENCLAW_STATE_DIR": stateDir.path,
|
||||
"OPENCLAW_CONFIG_PATH": configPath.path,
|
||||
]) {
|
||||
try OpenClawConfigFile.withTestingFileLock {
|
||||
let loaded = OpenClawConfigFile.loadDict()
|
||||
let update = loaded["update"] as? [String: Any]
|
||||
#expect(update?["channel"] as? String == "beta")
|
||||
#expect(!FileManager().fileExists(atPath: auditPath.path))
|
||||
let persistedHealth = try String(contentsOf: configHealthPath, encoding: .utf8)
|
||||
#expect(persistedHealth == legacyHealth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
@Test
|
||||
func `load dict audits suspicious out-of-band clobbers`() async throws {
|
||||
@@ -273,6 +325,7 @@ struct OpenClawConfigFileTests {
|
||||
.appendingPathComponent("openclaw-state-\(UUID().uuidString)", isDirectory: true)
|
||||
let configPath = stateDir.appendingPathComponent("openclaw.json")
|
||||
let auditPath = stateDir.appendingPathComponent("logs/config-audit.jsonl")
|
||||
let configHealthPath = stateDir.appendingPathComponent("logs/config-health.json")
|
||||
|
||||
defer { try? FileManager().removeItem(at: stateDir) }
|
||||
|
||||
@@ -293,6 +346,7 @@ struct OpenClawConfigFileTests {
|
||||
],
|
||||
])
|
||||
_ = OpenClawConfigFile.loadDict()
|
||||
#expect(!FileManager().fileExists(atPath: configHealthPath.path))
|
||||
|
||||
let clobbered = """
|
||||
{
|
||||
@@ -305,6 +359,7 @@ struct OpenClawConfigFileTests {
|
||||
|
||||
let loaded = OpenClawConfigFile.loadDict()
|
||||
#expect((loaded["gateway"] as? [String: Any]) == nil)
|
||||
#expect(!FileManager().fileExists(atPath: configHealthPath.path))
|
||||
|
||||
let rawAudit = try String(contentsOf: auditPath, encoding: .utf8)
|
||||
let lines = rawAudit
|
||||
|
||||
Reference in New Issue
Block a user