ForcePilot/backend/package/yuxi/channels/contract/dtos/audit.py
Kris 742299cb07 chore: 批量清理报告相关代码并完成多项功能迭代
本次提交包含多维度代码优化与功能增强:
1.  移除报告模块冗余导入与枚举,清理报表相关代码
2.  新增扫码登录支持方法与飞书适配器适配
3.  完善异常日志与健康检查信息
4.  扩展目录、配对管理、能力查询等接口
5.  优化出站管道与事务提交后钩子逻辑
6.  修复飞书消息解析与响应空值问题
7.  重构配置更新与服务账号创建逻辑
8.  统一传输错误分类契约与错误基类扩展
2026-07-06 20:49:35 +08:00

424 lines
18 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""审计 DTO。
定义审计日志的不可变值对象,包括审计日志 ID、审计操作类型、审计条目、审计
查询、审计统计聚合与审计导出任务。所有 DTO 均为 ``dataclass(frozen=True)``
仅依赖标准库与契约层内部类型,用于审计日志记录、查询、统计与导出。
"""
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from enum import StrEnum
from typing import Any, Literal
from yuxi.channels.contract.dtos.channel import ChannelType
from yuxi.channels.contract.dtos.common import Operator
from yuxi.channels.contract.errors import ValidationError
@dataclass(frozen=True)
class AuditLogId:
"""审计日志 ID。
标识一条审计日志的全局唯一 ID用于审计日志关联与查询。
字段:
value: 审计日志 ID 字符串。
"""
value: str
class AuditOperationType(StrEnum):
"""审计操作类型。
标识审计日志记录的操作类型,覆盖插件生命周期、能力声明、白名单、配对、
管理员消息、DM 决策、配置变更、Outbox 状态、诊断导出、账户生命周期与
扫码登录等场景。继承 ``str, Enum`` 以支持 JSON 序列化与字符串比较。
取值:
PLUGIN_DISCOVERED: 插件发现。
PLUGIN_LOADED: 插件加载。
PLUGIN_STARTED: 插件启动。
PLUGIN_STOPPED: 插件停止。
PLUGIN_UNLOADED: 插件卸载。
PLUGIN_FAILED: 插件失败。
PLUGIN_PAUSED: 插件暂停。
PLUGIN_RESUMED: 插件恢复。
PLUGIN_RELOADED: 插件重载FR-32unload + load 组合操作)。
PLUGIN_RECOVERED: 插件从失败降级中恢复FR-36对称于 PLUGIN_FAILED
CAPABILITY_DECLARED: 能力声明。
CAPABILITY_VERIFIED: 能力验证。
CAPABILITY_CHANGED: 能力变更。
WHITELIST_ADDED: 白名单添加。
WHITELIST_REMOVED: 白名单移除。
WHITELIST_CLEARED: 白名单清空。
PAIRING_CREATED: 配对创建。
PAIRING_APPROVED: 配对批准。
PAIRING_REJECTED: 配对拒绝。
PAIRING_REVOKED: 配对撤销。
PAIRING_EXPIRED: 配对过期。
ADMIN_MESSAGE_SENT: 管理员消息发送。
MESSAGE_RECALLED: 消息撤回MSG-05
DM_DECISION_ALLOW: DM 决策允许。
DM_DECISION_DENY: DM 决策拒绝。
DM_DECISION_PENDING: DM 决策待定。
CONFIG_CHANGED: 配置变更。
OUTBOX_STATE_CHANGED: Outbox 状态变更。
DIAGNOSTICS_EXPORTED: 诊断导出。
CHANNEL_PROBED: 渠道主动探测FR-35
SESSION_MERGED: 会话合并。
SESSION_OWNER_TRANSFERRED: 会话所有者转移FR-26
ADMIN_QUERY: 管理查询(目录列表 / 审计查询 / 健康详情等只读操作)。
DOCTOR_CHECK_LIST: 诊断检查项列表查询FR-17只读
DOCTOR_RUN: 全量诊断执行FR-17只读
DOCTOR_CHECK_ITEM: 单项诊断执行FR-17只读
DOCTOR_REPAIR: 诊断自动修复执行FR-17 / AC-40写操作
DOCTOR_REPAIR_PREVIEWED: 诊断修复预览FR-17 / AC-40dry-run 只读)。
WIZARD_APPLY: 安装向导步骤应用FR-16
WIZARD_FINALIZE: 安装向导完成FR-16
WIZARD_OAUTH_CALLBACK: 安装向导 OAuth 回调FR-16
ACCOUNT_CREATED: 账户创建AL-01
ACCOUNT_UPDATED: 账户配置更新AL-01
ACCOUNT_DELETED: 账户删除AL-04
ACCOUNT_ENABLED: 账户启用回调成功或无回调AL-02
ACCOUNT_DISABLED: 账户禁用回调成功或无回调AL-02
ACCOUNT_ENABLED_WARN: 账户启用回调失败AL-02
ACCOUNT_DISABLED_WARN: 账户禁用回调失败AL-02
AFTER_CONFIG_WRITTEN_OK: 配置写入后回调成功AL-03
AFTER_CONFIG_WRITTEN_WARN: 配置写入后回调失败AL-03
ACCOUNT_DELETE_CLEANUP_OK: 删除前清理回调成功AL-04
ACCOUNT_DELETE_CLEANUP_WARN: 删除前清理回调失败AL-04
START_QR_LOGIN: 发起扫码登录QR-06
QR_LOGIN_SUCCESS: 扫码登录成功QR-06
QR_LOGIN_FAILED: 扫码登录失败QR-06
QR_LOGIN_TIMEOUT: 扫码登录超时QR-06
QR_LOGIN_CANCELLED: 扫码取消QR-06
QR_REFRESH: 扫码刷新QR-06
LOGOUT: 登出QR-06
CONTENT_REVIEW_PREVIEWED: 内容预审核CR-01本期使用
CONTENT_REVIEW_BLOCKED: 内容审核命中 block预留本期不使用
未来管道自动审核命中 block 时记录)。
REPORT_CREATED: 报告创建。
REPORT_DOWNLOADED: 报告下载。
AGENT_LIST: Agent 列表查询(多 Agent 协作,只读)。
AGENT_GET: Agent 详情查询(多 Agent 协作,只读)。
AGENT_HANDOFF: Agent 移交执行(多 Agent 协作,写操作)。
AGENT_CONTEXT: Agent 上下文查询(多 Agent 协作,只读)。
SESSION_CLOSED: 会话关闭。
OUTBOX_DEAD_LETTER_BATCH_RETRIED: Outbox 死信批量重投。
OUTBOX_DEAD_LETTER_BATCH_DELETED: Outbox 死信批量删除。
OUTBOX_RETRY_POLICY_UPDATED: Outbox 重试策略更新。
PAIRING_REQUEST_CREATED: 配对请求创建。
ACCOUNT_CREDENTIALS_ROTATED: 账户凭据轮换。
ACCOUNT_CONNECTION_TESTED: 账户连接测试。
AUDIT_EXPORTED: 审计日志导出(同步导出)。
"""
PLUGIN_DISCOVERED = "plugin_discovered"
PLUGIN_LOADED = "plugin_loaded"
PLUGIN_STARTED = "plugin_started"
PLUGIN_STOPPED = "plugin_stopped"
PLUGIN_UNLOADED = "plugin_unloaded"
PLUGIN_FAILED = "plugin_failed"
PLUGIN_PAUSED = "plugin_paused"
PLUGIN_RESUMED = "plugin_resumed"
PLUGIN_RELOADED = "plugin_reloaded"
PLUGIN_RECOVERED = "plugin_recovered"
CAPABILITY_DECLARED = "capability_declared"
CAPABILITY_VERIFIED = "capability_verified"
CAPABILITY_CHANGED = "capability_changed"
WHITELIST_ADDED = "whitelist_added"
WHITELIST_REMOVED = "whitelist_removed"
WHITELIST_CLEARED = "whitelist_cleared"
PAIRING_CREATED = "pairing_created"
PAIRING_APPROVED = "pairing_approved"
PAIRING_REJECTED = "pairing_rejected"
PAIRING_REVOKED = "pairing_revoked"
PAIRING_EXPIRED = "pairing_expired"
ADMIN_MESSAGE_SENT = "admin_message_sent"
MESSAGE_RECALLED = "message_recalled"
DM_DECISION_ALLOW = "dm_decision_allow"
DM_DECISION_DENY = "dm_decision_deny"
DM_DECISION_PENDING = "dm_decision_pending"
CONFIG_CHANGED = "config_changed"
OUTBOX_STATE_CHANGED = "outbox_state_changed"
DIAGNOSTICS_EXPORTED = "diagnostics_exported"
CHANNEL_PROBED = "channel_probed"
SESSION_MERGED = "session_merged"
SESSION_OWNER_TRANSFERRED = "session_owner_transferred"
ADMIN_QUERY = "admin_query"
DOCTOR_CHECK_LIST = "doctor_check_list"
DOCTOR_RUN = "doctor_run"
DOCTOR_CHECK_ITEM = "doctor_check_item"
DOCTOR_REPAIR = "doctor_repair"
DOCTOR_REPAIR_PREVIEWED = "doctor_repair_previewed"
WIZARD_APPLY = "wizard_apply"
WIZARD_FINALIZE = "wizard_finalize"
WIZARD_OAUTH_CALLBACK = "wizard_oauth_callback"
# 账户生命周期审计类型AL-01~AL-04
ACCOUNT_CREATED = "account_created"
ACCOUNT_UPDATED = "account_updated"
ACCOUNT_DELETED = "account_deleted"
ACCOUNT_ENABLED = "account_enabled"
ACCOUNT_DISABLED = "account_disabled"
ACCOUNT_ENABLED_WARN = "account_enabled_warn"
ACCOUNT_DISABLED_WARN = "account_disabled_warn"
AFTER_CONFIG_WRITTEN_OK = "after_config_written_ok"
AFTER_CONFIG_WRITTEN_WARN = "after_config_written_warn"
ACCOUNT_DELETE_CLEANUP_OK = "account_delete_cleanup_ok"
ACCOUNT_DELETE_CLEANUP_WARN = "account_delete_cleanup_warn"
# 扫码登录审计类型QR-06
START_QR_LOGIN = "start_qr_login"
QR_LOGIN_SUCCESS = "qr_login_success"
QR_LOGIN_FAILED = "qr_login_failed"
QR_LOGIN_TIMEOUT = "qr_login_timeout"
QR_LOGIN_CANCELLED = "qr_login_cancelled"
QR_REFRESH = "qr_refresh"
LOGOUT = "logout"
# 内容审核审计类型CR-01 / 管道自动审核)
CONTENT_REVIEW_PREVIEWED = "content_review_previewed"
CONTENT_REVIEW_BLOCKED = "content_review_blocked" # 预留:管道自动审核命中 block 时记录
# 多 Agent 协作审计类型
AGENT_LIST = "agent_list"
AGENT_GET = "agent_get"
AGENT_HANDOFF = "agent_handoff"
AGENT_CONTEXT = "agent_context"
# 会话关闭审计类型
SESSION_CLOSED = "session_closed"
# Outbox 死信批量操作审计类型
OUTBOX_DEAD_LETTER_BATCH_RETRIED = "outbox_dead_letter_batch_retried"
OUTBOX_DEAD_LETTER_BATCH_DELETED = "outbox_dead_letter_batch_deleted"
OUTBOX_RETRY_POLICY_UPDATED = "outbox_retry_policy_updated"
# 配对请求创建审计类型
PAIRING_REQUEST_CREATED = "pairing_request_created"
# 账户凭据轮换与连接测试审计类型
ACCOUNT_CREDENTIALS_ROTATED = "account_credentials_rotated"
ACCOUNT_CONNECTION_TESTED = "account_connection_tested"
# 强制下线审计类型LGN-FORCE-LOGOUT
ACCOUNT_OFFLINE = "account_offline"
# 目录缓存清理审计类型DIR-CACHE-CLEAR
DIRECTORY_CACHE_CLEARED = "directory_cache_cleared"
# 审计日志导出(同步导出,区别于 admin_query 查询)
AUDIT_EXPORTED = "audit_exported"
class AuditTxStrategy(StrEnum):
"""审计事务策略。
标识控制面操作产生副作用的可回滚性,决定 audit 阶段的事务边界。
继承 ``str, Enum`` 以支持 JSON 序列化与字符串比较。
取值:
SHARED: 共享事务fail-closed。适用于纯 DB 写入或只读操作,
审计与业务写入原子提交审计失败回滚业务FR-34 fail-closed
INDEPENDENT: 独立事务best-effort。适用于已产生不可回滚外部
副作用的操作IM 发送、Redis 写入、事件发布),审计使用独立
事务,失败时仅记录告警,不中止业务——避免"外部副作用已发生
但审计回滚导致无痕迹"§10.1 事务边界)。
"""
SHARED = "shared"
INDEPENDENT = "independent"
@dataclass(frozen=True)
class AuditEntry:
"""审计条目。
描述一条审计日志的完整内容,包括操作人、操作类型、目标、参数摘要、结果、
时间戳与链路追踪信息,用于审计日志持久化与查询。
字段:
operator: 操作人(用户 ID 或 "system")。
operation: 操作类型。
target: 操作目标。
result: 操作结果success | failed
timestamp: 操作时间戳。
params_summary: 脱敏后的参数摘要(可选)。
trace_id: 链路追踪 ID可选
source_ip: 来源 IP可选FR-34
request_id: 请求 ID可选链路追踪用FR-34
message_id: 关联消息 ID可选FR-19
content_summary: 消息内容摘要可选FR-19
target_channel: 目标渠道类型可选FR-34 审计日志按渠道作用域)。
target_account: 目标账户 ID可选FR-34 按账户作用域查询)。
"""
operator: str
operation: AuditOperationType
target: str
result: Literal["success", "failed"]
timestamp: datetime
params_summary: dict[str, Any] | None = None
trace_id: str | None = None
source_ip: str | None = None
request_id: str | None = None
message_id: str | None = None
content_summary: str | None = None
target_channel: str | None = None
target_account: str | None = None
@dataclass(frozen=True)
class AuditQuery:
"""审计查询AUD-001
描述审计日志查询条件,支持按操作类型、操作人、目标渠道、目标账户、
时间范围与分页过滤。管理员审计日志 API 的作用域为"按渠道类型+账户"
PRD FR-34target_channel 与 target_account 共同确定查询范围。
字段:
operation_type: 操作类型(可选)。
operator: 操作人(可选)。
target_channel: 目标渠道(可选)。
target_account: 目标账户可选FR-34 按账户作用域查询)。
start_time: 起始时间(可选)。
end_time: 结束时间(可选)。
limit: 分页大小(默认 100
offset: 分页偏移(默认 0
trace_id: 链路追踪 ID可选按链路追踪 ID 过滤)。
"""
operation_type: AuditOperationType | None = None
operator: str | None = None
target_channel: ChannelType | None = None
target_account: str | None = None
start_time: datetime | None = None
end_time: datetime | None = None
limit: int = 100
offset: int = 0
trace_id: str | None = None
def __post_init__(self) -> None:
"""校验时间范围与分页参数。
``start_time`` 与 ``end_time`` 同时提供时,``start_time`` 必须早于
``end_time````limit`` 必须为正整数,``offset`` 必须为非负整数。
在构造时即抛出 ``ValidationError``adapter 不再做该校验INV-8
"""
if self.start_time is not None and self.end_time is not None:
if self.start_time >= self.end_time:
raise ValidationError(
"time_range",
"start_time must be earlier than end_time",
)
if self.limit <= 0:
raise ValidationError("limit", "must be a positive integer")
if self.offset < 0:
raise ValidationError("offset", "must be a non-negative integer")
@dataclass(frozen=True)
class AuditLogStats:
"""审计日志统计聚合结果。
描述审计日志按操作类型、操作结果分组的计数与时间范围,由
``getAuditLogStats`` 返回,供管理后台展示审计日志分布与合规报表。
字段:
total: 满足过滤条件的审计日志总数。
by_operation_type: 按操作类型分组的计数key 为 operation_type 字符串)。
by_result: 按操作结果分组的计数key 为 "success" / "failed")。
time_range_start: 匹配记录的最早时间戳(无数据时为 None
time_range_end: 匹配记录的最晚时间戳(无数据时为 None
"""
total: int
by_operation_type: dict[str, int]
by_result: dict[str, int]
time_range_start: datetime | None
time_range_end: datetime | None
@dataclass(frozen=True)
class RetentionPolicy:
"""审计保留策略AUD-RETENTION
描述审计日志的保留策略配置,包括默认保留天数、按操作类型的保留天数、
自动归档开关与归档提前天数,由 ConfigManager 管理
``audit_retention_policy`` 配置键GLOBAL 作用域)。
字段:
default_retention_days: 默认保留天数。
by_operation_type: 按操作类型分组的保留天数key 为
AuditOperationType 字符串值)。
auto_archive_enabled: 是否启用自动归档。
auto_archive_before_days: 归档提前天数(到期前 N 天归档)。
updated_at: 策略最后更新时间(可选,未更新时为 None
"""
default_retention_days: int
by_operation_type: dict[str, int]
auto_archive_enabled: bool
auto_archive_before_days: int
updated_at: datetime | None = None
@dataclass(frozen=True)
class RetentionPolicyUpdateCmd:
"""审计保留策略更新命令AUD-RETENTION-PUT
由 ``AuditQueryPort.updateRetentionPolicy`` 引用,更新审计日志保留策略,
需记录操作人以满足审计要求PUT 需超级管理员)。
字段:
operator: 操作人(审计用)。
default_retention_days: 默认保留天数(默认 90
by_operation_type: 按操作类型分组的保留天数(可选)。
auto_archive_enabled: 是否启用自动归档(默认 True
auto_archive_before_days: 归档提前天数(默认 80
"""
operator: Operator
default_retention_days: int = 90
by_operation_type: dict[str, Any] | None = None
auto_archive_enabled: bool = True
auto_archive_before_days: int = 80
def __post_init__(self) -> None:
"""校验业务规则INV-8 / 端口 @pre
- ``default_retention_days`` 与 ``auto_archive_before_days`` 必须为正整数。
- ``auto_archive_before_days`` 必须小于 ``default_retention_days``。
- ``by_operation_type``(如提供)的 key 必须为合法的
``AuditOperationType`` 字符串值value 必须为正整数。
在构造时即抛出 ``ValidationError``,避免非法值传播到 dispatch 阶段。
"""
if self.default_retention_days <= 0:
raise ValidationError("default_retention_days", "must be positive")
if self.auto_archive_before_days <= 0:
raise ValidationError("auto_archive_before_days", "must be positive")
if self.auto_archive_before_days >= self.default_retention_days:
raise ValidationError(
"auto_archive_before_days",
"must be less than default_retention_days",
)
if self.by_operation_type is not None:
valid_keys = {e.value for e in AuditOperationType}
for k, v in self.by_operation_type.items():
if k not in valid_keys:
raise ValidationError(
"by_operation_type",
f"invalid operation_type key: {k}",
)
if not isinstance(v, int) or isinstance(v, bool) or v <= 0:
raise ValidationError(
"by_operation_type",
f"value for '{k}' must be positive int, got {v!r}",
)
__all__ = [
"AuditEntry",
"AuditLogId",
"AuditLogStats",
"AuditOperationType",
"AuditQuery",
"AuditTxStrategy",
"RetentionPolicy",
"RetentionPolicyUpdateCmd",
]