fix: add diagnostic warnings for config loading failures (#91)

When config files have errors, users had no way to know why their
settings weren't being applied. Added logging.warning() calls to
diagnose:
- Empty config files
- Missing 'version' field
- Invalid structure (not a dict)
- Invalid command entries
- Exceeding 100 command limit
- YAML parse errors
- File read errors

Also added .resolve() to project path to handle symlinks correctly.

Fixes: leonvanzyl/autocoder#91

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
cabana8471
2026-01-25 12:08:53 +01:00
parent 836bc8ae16
commit 1d67fff9e0

View File

@@ -499,36 +499,45 @@ def load_org_config() -> Optional[dict]:
config = yaml.safe_load(f)
if not config:
logger.warning(f"Org config at {config_path} is empty")
return None
# Validate structure
if not isinstance(config, dict):
logger.warning(f"Org config at {config_path} must be a YAML dictionary")
return None
if "version" not in config:
logger.warning(f"Org config at {config_path} missing required 'version' field")
return None
# Validate allowed_commands if present
if "allowed_commands" in config:
allowed = config["allowed_commands"]
if not isinstance(allowed, list):
logger.warning(f"Org config at {config_path}: 'allowed_commands' must be a list")
return None
for cmd in allowed:
for i, cmd in enumerate(allowed):
if not isinstance(cmd, dict):
logger.warning(f"Org config at {config_path}: allowed_commands[{i}] must be a dict")
return None
if "name" not in cmd:
logger.warning(f"Org config at {config_path}: allowed_commands[{i}] missing 'name'")
return None
# Validate that name is a non-empty string
if not isinstance(cmd["name"], str) or cmd["name"].strip() == "":
logger.warning(f"Org config at {config_path}: allowed_commands[{i}] has invalid 'name'")
return None
# Validate blocked_commands if present
if "blocked_commands" in config:
blocked = config["blocked_commands"]
if not isinstance(blocked, list):
logger.warning(f"Org config at {config_path}: 'blocked_commands' must be a list")
return None
for cmd in blocked:
for i, cmd in enumerate(blocked):
if not isinstance(cmd, str):
logger.warning(f"Org config at {config_path}: blocked_commands[{i}] must be a string")
return None
# Validate pkill_processes if present
@@ -550,7 +559,11 @@ def load_org_config() -> Optional[dict]:
return config
except (yaml.YAMLError, IOError, OSError):
except yaml.YAMLError as e:
logger.warning(f"Failed to parse org config at {config_path}: {e}")
return None
except (IOError, OSError) as e:
logger.warning(f"Failed to read org config at {config_path}: {e}")
return None
@@ -564,7 +577,7 @@ def load_project_commands(project_dir: Path) -> Optional[dict]:
Returns:
Dict with parsed YAML config, or None if file doesn't exist or is invalid
"""
config_path = project_dir / ".autocoder" / "allowed_commands.yaml"
config_path = project_dir.resolve() / ".autocoder" / "allowed_commands.yaml"
if not config_path.exists():
return None
@@ -574,31 +587,39 @@ def load_project_commands(project_dir: Path) -> Optional[dict]:
config = yaml.safe_load(f)
if not config:
logger.warning(f"Project config at {config_path} is empty")
return None
# Validate structure
if not isinstance(config, dict):
logger.warning(f"Project config at {config_path} must be a YAML dictionary")
return None
if "version" not in config:
logger.warning(f"Project config at {config_path} missing required 'version' field")
return None
commands = config.get("commands", [])
if not isinstance(commands, list):
logger.warning(f"Project config at {config_path}: 'commands' must be a list")
return None
# Enforce 100 command limit
if len(commands) > 100:
logger.warning(f"Project config at {config_path} exceeds 100 command limit ({len(commands)} commands)")
return None
# Validate each command entry
for cmd in commands:
for i, cmd in enumerate(commands):
if not isinstance(cmd, dict):
logger.warning(f"Project config at {config_path}: commands[{i}] must be a dict")
return None
if "name" not in cmd:
logger.warning(f"Project config at {config_path}: commands[{i}] missing 'name'")
return None
# Validate name is a string
if not isinstance(cmd["name"], str):
# Validate name is a non-empty string
if not isinstance(cmd["name"], str) or cmd["name"].strip() == "":
logger.warning(f"Project config at {config_path}: commands[{i}] has invalid 'name'")
return None
# Validate pkill_processes if present
@@ -620,7 +641,11 @@ def load_project_commands(project_dir: Path) -> Optional[dict]:
return config
except (yaml.YAMLError, IOError, OSError):
except yaml.YAMLError as e:
logger.warning(f"Failed to parse project config at {config_path}: {e}")
return None
except (IOError, OSError) as e:
logger.warning(f"Failed to read project config at {config_path}: {e}")
return None