Skip to content

08 · 安全与监控 ​

架构剖析第八篇:工具审批门、敏感信息检测、加密存储、认证系统、Monitor / Daily Monitor、Cron / Schedule / Todo / Reminder。 对应 ARCHITECTURE.md §9–§10。


§9.1 安全模型 ​

9.1.1 风险分级 ​

src/tools/security.py 定义工具风险等级:

python
_LEVELS = {"low": 0, "medium": 1, "high": 2, "super": 99}
等级值说明审批规则
low0只读/无害不审批
medium1写文件/编辑默认审批
high2执行代码/删除/网络必须审批
super99极高风险永远审批(用户阈值无法覆盖)

9.1.2 用户阈值 ​

python
"low"    → 审批所有工具 (low + medium + high)
"medium" → 审批 medium + high    ← 默认
"high"   → 审批仅 high           ← 最宽松

FAMILIARS_APPROVAL_DISABLED=1 → 完全跳过审批门(无attended batch runs)。

9.1.3 Score-based 动态升级 ​

每个工具有基础分,工具参数中的 PII/凭证类型加成分:

[0, 30)  → "low"
[30, 60) → "medium"
[60, 90) → "high"
90+      → "super"

工具基础分 ​

python
TOOL_BASE_SCORE: dict[str, int] = {
    "write":                45,   # medium;内容可升级
    "edit":                 40,
    "write_csv":            40,
    "write_memory":         40,
    "delete_file":          65,   # high
    "move_or_rename":       65,
    "download":             65,
    "execute_shell_script": 70,
    "execute_python_file":  70,
    "execute_node_file":    70,
    "run_pip":              70,
    "run_npm":              70,
    "run_git":              65,
    "ssh_exec":             70,
    "sqlite_query":         65,
    "http_request":         45,
    "scp_upload":           65,
    "send_email":           65,
    "social_send":          65,
    "keyboard_type":        65,
    "browser_type":         65,
}

敏感参数加分 ​

python
SENSITIVE_ARG_SCORE: dict[str, int] = {
    "aws-access-key":       50,
    "aws-secret-key":       50,
    "github-pat":           50,
    "github-fine-grained":  50,
    "openai-key":           50,
    "anthropic-key":        50,
    "google-api-key":       50,
    "slack-token":          40,
    "private-key-pem":      50,
    # ...
}

示例:write(path, content) 含银行卡号 → 45 + 45 = 90 → 升级到 super。

9.1.4 requires_approval 包装器 ​

python
# src/tools/security.py
def requires_approval(func):
    """装饰器,包装工具方法。
    
    1. 查 UserConfig.security_level → 与工具风险比较
    2. tool_risk >= user_threshold → 发 ApprovalRequest 到 CommHub
    3. 阻塞等待用户审批(有超时)
    4. 批准 → 执行原方法;拒绝/超时 → PermissionError
    """

§9.2 敏感信息检测(src/tools/sensitive_detector.py) ​

9.2.1 三层检测 ​

Layer 1: gitleaks  → 高置信度正则/熵检测(凭证、token、key)
Layer 2: presidio  → Microsoft-Presidio PII(PERSON, EMAIL, PHONE, IP, ...)
Layer 3: mini-LLM  → 最后兜底(项目代号、自定义 ID、雇主名)

9.2.2 Finding 数据结构 ​

python
@dataclass
class Finding:
    value: str      # 字面子串(明文,永不记录日志)
    start: int
    end: int
    kind: str       # "credential" | "pii" | "custom"
    rule: str       # 检测规则 id
    layer: str      # "gitleaks" | "presidio" | "mini_llm"
    score: float = 1.0

9.2.3 Gitleaks 回退正则 ​

python
_GITLEAKS_FALLBACK: list[tuple[str, re.Pattern]] = [
    ("aws-access-key",       re.compile(r"\bAKIA[0-9A-Z]{16}\b")),
    ("aws-secret-key",       re.compile(r"(?i)aws[^\s'\"]{0,20}['\"][0-9a-zA-Z/+]{40}['\"]")),
    ("github-pat",           re.compile(r"\bghp_[A-Za-z0-9]{36}\b")),
    ("openai-key",           re.compile(r"\bsk-(?:proj-)?[A-Za-z0-9_-]{20,}\b")),
    ("anthropic-key",        re.compile(r"\bsk-ant-[A-Za-z0-9_-]{20,}\b")),
    ("slack-token",          re.compile(r"\bxox[abprs]-[A-Za-z0-9-]{10,}\b")),
    ("google-api-key",       re.compile(r"\bAIza[0-9A-Za-z_-]{35}\b")),
    ("private-key-pem",      re.compile(r"-----BEGIN [A-Z ]*PRIVATE KEY-----...")),
    ("jwt",                  re.compile(r"\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b")),
    # ...
]

9.2.4 提交流程 ​

检测后,每个 finding 配 1-2 句上下文 → mini 模型命名(key + type + aliases)→ KV 加密 → workspace/SECRET.json → 可通过 get_user_secret 工具召回。

永不在日志或持久化中保留明文。

§9.3 加密存储(src/base/crypto.py) ​

hostname + username + salt_bytes
    → HKDF (SHA-256, info=b"familiars-secrets-v1")
    → 32-byte Fernet key
    → AES-128-CBC + HMAC-SHA256 加密
    → workspace/SECRET.json
python
_SALT_FILENAME = ".salt"
_KEY_INFO = b"familiars-secrets-v1"

def _derive_fernet_key() -> bytes:
    salt = _load_or_create_salt()        # os.urandom(32)
    identity = f"{platform.node()}|{os.getenv('USER', ...)}"
    hkdf = HKDF(algorithm=hashes.SHA256(), length=32, salt=salt, info=_KEY_INFO)
    raw_key = hkdf.derive(identity.encode("utf-8"))
    return base64.urlsafe_b64encode(raw_key)

安全不变量:

  • salt 文件无机器身份无用
  • 机器身份无 salt 无用
  • HKDF info 字符串是版本化密码原语 → 改它使所有已存密钥失效

§9.4 认证(src/base/auth/) ​

src/base/auth/
├── __init__.py          # get_auth_manager()
├── app.py               # AuthManager 实现
├── manager.py           # 认证管理逻辑
├── models.py            # 认证数据模型
└── device.py            # 设备指纹(macOS 有真实实现,Windows 仅 hostname)

9.4.1 Bridge Token ​

python
# src/base/bridge_token.py
def verify_bridge_token(token: str) -> bool:
    """验证 X-Bridge-Token 或 ?token= 参数。"""

# 存储在 workspace/.bridge_token
# 首次启动自动生成

9.4.2 设备指纹 ​

src/base/auth/device.py:

  • macOS:有真实实现(Keychain / IOKit)
  • Windows:仅 hostname fingerprint(不稳定)

§9.5 本地 Monitor ​

9.5.1 社交平台监听 ​

平台实现模块
微信wcferry.Wcfsrc/utils/daily_tools.py
QQUI Automationsrc/utils/daily_tools.py
飞书Webhooksrc/bridge/routes/feishu.py

9.5.2 屏幕/麦克风 ​

  • 需 OS 授权 + 应用内审批
  • macOS: Quartz, AppKit.NSWorkspace, ApplicationServices
  • Windows: pyautogui, uiautomation

§9.6 Daily Monitor ​

python
# src/utils/daily_monitor/__init__.py
class DailyMonitorTools:
    """每天主动收集上下文:
    - 消息聚合
    - 日程摘要
    - 网络信息
    → 供 agent 生成"今日摘要/明天建议"
    """

§9.7 Cron / Schedule / Todo / Reminder ​

9.7.1 APScheduler 集成 ​

python
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.cron import CronTrigger
from apscheduler.triggers.interval import IntervalTrigger

9.7.2 报告生成 ​

  • 每日/每周/每月/每年报告 → APScheduler cron
  • 已由 manager_review skill 替代旧 write_report()
  • 按 agent 对话轮次阈值触发

9.7.3 数据集中化 ​

所有调度数据存 familiars.db:

表用途
cron_jobsCron 定义
cron_runsCron 运行记录
schedules日程
todos待办
reminders提醒
watch_jobs监控作业

前端各处读写同一套,REST 端点:

  • POST /api/cron — Cron CRUD
  • POST /api/schedule — 日程 CRUD
  • POST /api/todo — 待办 CRUD
  • GET /api/reminders/stream — 提醒 SSE

下一篇:09-生态总览 →

Familiars · 多 Agent AI 桌面应用