from __future__ import annotations import ast from pathlib import Path import pytest _FEISHU_FILES = ( "chat.py", "feishu_client.py", ) _CREDENTIAL_NAMES = {"FEISHU_APP_ID", "FEISHU_APP_SECRET"} @pytest.mark.parametrize("filename", _FEISHU_FILES) def test_legacy_feishu_credentials_have_no_nonempty_fallback(filename: str) -> None: path = ( Path(__file__).parents[1] / "agent" / "tools" / "builtin" / "feishu" / filename ) tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path)) for node in ast.walk(tree): if not isinstance(node, ast.Call) or not isinstance(node.func, ast.Attribute): continue if node.func.attr != "getenv" or not node.args: continue name = node.args[0] if not isinstance(name, ast.Constant) or name.value not in _CREDENTIAL_NAMES: continue if len(node.args) > 1: fallback = node.args[1] assert isinstance(fallback, ast.Constant) assert fallback.value in {None, ""} for node in ast.walk(tree): if not isinstance(node, ast.Assign) or not isinstance(node.value, ast.Constant): continue for target in node.targets: if not isinstance(target, ast.Subscript): continue key = target.slice if isinstance(key, ast.Constant) and key.value in _CREDENTIAL_NAMES: assert node.value.value in {None, ""}