Claude Code commited on
Commit
a7c437d
·
1 Parent(s): af77dd8

Claude Code: Fix the two critical bugs identified in the audit:

Browse files
Files changed (2) hide show
  1. memory/cain.py +33 -2
  2. scripts/sync_hf.py +33 -5
memory/cain.py CHANGED
@@ -4,19 +4,50 @@ Lightweight state management to ensure persistence without heavy dependencies.
4
  """
5
  import json
6
  import os
 
 
 
 
7
 
8
  class Memory:
9
  def __init__(self, persist_path="/data/memory/state.json"):
10
  self.persist_path = persist_path
11
- self.state = self._load()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  def _load(self):
14
  if os.path.exists(self.persist_path):
15
  try:
16
  with open(self.persist_path, 'r') as f:
17
  return json.load(f)
18
- except Exception:
 
 
 
 
19
  return {"status": "clean_slate", "runs": 0}
 
20
  return {"status": "born", "runs": 0}
21
 
22
  def save(self):
 
4
  """
5
  import json
6
  import os
7
+ import logging
8
+ from pathlib import Path
9
+
10
+ logger = logging.getLogger(__name__)
11
 
12
  class Memory:
13
  def __init__(self, persist_path="/data/memory/state.json"):
14
  self.persist_path = persist_path
15
+ self._ensure_directory_writable()
16
+ try:
17
+ self.state = self._load()
18
+ except (OSError, IOError, json.JSONDecodeError) as e:
19
+ logger.warning(f"Failed to load state from {self.persist_path}: {e}")
20
+ self.state = {"status": "clean_slate", "runs": 0}
21
+
22
+ def _ensure_directory_writable(self):
23
+ """Validate and create the persist_path directory if needed."""
24
+ persist_path = Path(self.persist_path)
25
+ parent_dir = persist_path.parent
26
+
27
+ # Create directory if it doesn't exist
28
+ try:
29
+ parent_dir.mkdir(parents=True, exist_ok=True)
30
+ except (OSError, PermissionError) as e:
31
+ logger.error(f"Cannot create directory {parent_dir}: {e}")
32
+ raise
33
+
34
+ # Verify directory is writable
35
+ if not os.access(parent_dir, os.W_OK):
36
+ logger.error(f"Directory {parent_dir} is not writable")
37
+ raise PermissionError(f"Cannot write to {parent_dir}")
38
 
39
  def _load(self):
40
  if os.path.exists(self.persist_path):
41
  try:
42
  with open(self.persist_path, 'r') as f:
43
  return json.load(f)
44
+ except (json.JSONDecodeError, ValueError) as e:
45
+ logger.warning(f"Corrupt state file at {self.persist_path}: {e}")
46
+ return {"status": "clean_slate", "runs": 0}
47
+ except (OSError, IOError) as e:
48
+ logger.warning(f"Cannot read state file {self.persist_path}: {e}")
49
  return {"status": "clean_slate", "runs": 0}
50
+ logger.info(f"State file does not exist (first run): {self.persist_path}")
51
  return {"status": "born", "runs": 0}
52
 
53
  def save(self):
scripts/sync_hf.py CHANGED
@@ -470,17 +470,45 @@ class OpenClawFullSync:
470
  with open(config_path, "r") as f:
471
  data = json.load(f)
472
  print("[SYNC] Config parsed OK.")
473
- except (json.JSONDecodeError, Exception) as e:
474
  # Config is corrupt — back up and start fresh
475
  print(f"[SYNC] Config JSON is corrupt: {e}")
476
  backup = config_path.with_suffix(f".corrupt_{int(time.time())}")
477
  try:
478
  shutil.copy2(config_path, backup)
479
  print(f"[SYNC] Backed up corrupt config to {backup.name}")
480
- except Exception:
481
- pass
482
- data = {}
483
- print("[SYNC] Starting from clean config.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
484
 
485
  try:
486
  # Remove /dev/null from plugins.locations
 
470
  with open(config_path, "r") as f:
471
  data = json.load(f)
472
  print("[SYNC] Config parsed OK.")
473
+ except (json.JSONDecodeError, ValueError) as e:
474
  # Config is corrupt — back up and start fresh
475
  print(f"[SYNC] Config JSON is corrupt: {e}")
476
  backup = config_path.with_suffix(f".corrupt_{int(time.time())}")
477
  try:
478
  shutil.copy2(config_path, backup)
479
  print(f"[SYNC] Backed up corrupt config to {backup.name}")
480
+ except (IOError, PermissionError, OSError) as backup_err:
481
+ print(f"[SYNC] WARNING: Failed to back up corrupt config: {backup_err}")
482
+ # Ensure valid default config structure to avoid cascading failures
483
+ data = {
484
+ "gateway": {
485
+ "mode": "local",
486
+ "bind": "lan",
487
+ "port": 7860,
488
+ "trustedProxies": ["0.0.0.0/0"],
489
+ },
490
+ "session": {"scope": "global"},
491
+ "models": {"mode": "merge", "providers": {}},
492
+ "agents": {"defaults": {"workspace": "~/.openclaw/workspace"}}
493
+ }
494
+ print("[SYNC] Starting from clean config structure.")
495
+ except (IOError, PermissionError, OSError) as e:
496
+ # Filesystem error - cannot read config file
497
+ print(f"[SYNC] ERROR: Cannot read config file: {e}")
498
+ print(f"[SYNC] Check permissions and filesystem integrity for {config_path}")
499
+ # Ensure valid default config structure
500
+ data = {
501
+ "gateway": {
502
+ "mode": "local",
503
+ "bind": "lan",
504
+ "port": 7860,
505
+ "trustedProxies": ["0.0.0.0/0"],
506
+ },
507
+ "session": {"scope": "global"},
508
+ "models": {"mode": "merge", "providers": {}},
509
+ "agents": {"defaults": {"workspace": "~/.openclaw/workspace"}}
510
+ }
511
+ print("[SYNC] Using default config structure due to filesystem error.")
512
 
513
  try:
514
  # Remove /dev/null from plugins.locations