审计历史¶
Gateway 在共享的 OpenClaw 状态数据库中维护一个有界的、仅包含元数据的审计账本。它回答诸如“哪个代理运行了、何时运行、如何结束”、“某次运行执行了哪些工具操作”,以及在启用消息审计时,“已接受的入站消息是否到达分发”和“出站消息是否到达最终投递状态”等运维问题。
该账本存储身份、顺序、来源、操作、状态和规范化结果代码。它从不存储提示词、消息正文、工具参数、工具结果、附件、文件名、URL、命令输出或原始错误文本。
Gateway 还为新接受的代理运行维护一个相邻的执行身份上下文。该上下文对其包含的身份事实具有权威性;它不会使活动账本变得无损,也不会将审计记录变成授权证据。
终端操作员批准是另一个独立权威来源。运行检查会直接将这些现有的“首个答案生效”行适配为决策回执;它不会将批准复制到审计账本或通用决策事实表中。
这包括由操作员路由的原生 Codex 命令和文件提示。Codex 桥接会将已接受的代理、会话密钥、运行、工具、上下文和执行绑定带入同一个批准所有者,然后仅返回已批准的原生范围。自动审查、完全访问策略、原生钩子决策以及在操作员路由之前被拒绝的请求没有操作员拥有的行,并且仍不支持作为操作员批准证据;后续工具事件绝不会制造这样的证据。
共享出站投递是另一个所有者原生来源。队列接受和平台发送开始使用一个惰性进度伴随项,而终端消息行仍保留在活动账本中。运行检查直接合并这两个来源;两者都不会复制到通用决策事实表中。
计划运行也是一个所有者原生来源。在精确运行接受之后,一个惰性生命周期元数据表会将已接受的上下文和执行 ID 绑定到规范的 cron_run_receipts 行。检查会直接将该元数据与回执连接,并保留其记录的状态。新的任务和工作流生命周期绑定写入以及检查连接已弃用,但它们现有的表和行不会被删除或迁移。此移除使数据库架构保持不变;请参阅版本控制契约。独立的审计事件和决策事实保留其现有保留策略;它们不会从保留的 Task 或 TaskFlow 行中重建。仅凭 runId 永远不会将所有者行连接到执行。缺失、已删除、损坏或不匹配的绑定仍保持未知或不存在;它们永远不会改变执行行为,也永远不会被复制到 execution_decision_facts。
运行身份检查¶
执行身份记录默认关闭,包括在全新安装和升级时。请为新接受的运行显式启用它:
收集要求 logging.audit.enabled 和 logging.audit.executionIdentity 均为 true。将任一设置为 false 会立即停止新上下文;没有环境变量别名或静默迁移会启用该功能。保留的上下文在 30 天到期前仍可检查。
审计设置无需重启 Gateway 即可生效。更改会影响后续事件和接受;已接受的写入仍通过同一队列排空,且先前已接受的身份上下文保持不可变。启用收集不会回填较早的活动,也不会为已接受的运行添加身份。
在会话工作接受成功后,OpenClaw 会验证并冻结一个有界的身份信封,立即将其提供给现有的审计写入器队列,并继续运行,而不等待写入器就绪、SQLite 或持久化。队列排空会初始化架构和 HMAC 密钥状态,对原始引用进行假名化,构建不可变上下文,验证其规范字节,并通过现有共享状态工作器持久化。进程拥有的 FIFO 会保留每个已接受项,直到其工作器尝试结束。因此,在队列工作完成期间,已接受信封可能暂时无法检查。
持久化仍为尽力而为。队列饱和、存储故障、关闭超时和进程崩溃可能导致证据丢失;它们仅记录有界的运维警告,并且永远不会中止运行。当写入器生命周期允许时,正常的 Gateway 和直接本地 CLI 关闭会刷新已接受的工作,但突然终止仍可能丢失队列中的证据。
当启用身份收集时,重启恢复仅使用其现有私有恢复所有者存储安全的执行/上下文/运行 ID 和时间戳。后续的模糊重试会引用该令牌,而不是从新进程中重建身份。当收集或审计账本被禁用时,恢复不会创建、存储或传播新的身份令牌。如果原始队列上下文丢失,精确检查将明确保持不可用;重试绝不会制造替代证据。原始身份引用不会存储在恢复令牌中。
每个已接受的外层轮次都会获得一个新的不透明 executionId;contextId 标识其不可变证据记录,而现有的 runId 仍然是可能共享的路由、会话或恢复关联。使用 audit.run.inspect 或 openclaw audit --execution <id> --explain 查询一个精确执行。使用 --run <id> --explain 来发现某个运行关联的执行。一个保留的匹配项会直接解析。多个匹配项返回 ambiguous,最多包含 50 个候选执行 ID,并要求精确选择;OpenClaw 绝不会静默选择第一个或最新执行。结果会明确说明这些字段的证据状态:
- 信任域、调用方和入口;
- 代理主体、代理定义和运行时实例;
- 所代表的主体和发起人;
- 适用的授权和保证证据;
- 可用时的父级或子级谱系。
对于通过 sessions_spawn 启动的子级,子级拥有一个新的上下文;它从不复用或修改父级上下文。当确切的父级私有令牌可用时,谱系投影会将父级上下文、执行、运行和 agent 联系起来。其委托引用涵盖 spawn 关系以及请求者/控制者和已评估的本地/目标策略输入。适用的授权(grants)和运行时保证仍然是独立的证据类别。这报告了可能缩小子级权限的输入;它并不声称身份改变了允许或拒绝的决定。
如果父级私有令牌不可用,子级仍然可检查,但缺失的父级上下文、执行和运行证据是明确的。ACP 的 spawn 本身是可观测的。完全在外部 ACP 运行时内执行且没有回调的操作,会被报告为不支持的证据,绝不会从任务或转录文本中推断出来。准入后,ACP 生命周期所有者在提示提交时记录该回执,并使用确切的已准入执行令牌。它不声称发生了原生副作用;适配器作者必须添加权威的 native-action 回调,以提供更强的证据。
已注册的插件运行时调用仅在精确的运行准入之后添加有界事实。before_tool_call 钩子会将其自身的允许或阻止记录为强制的插件门禁;fail-closed(故障关闭)钩子错误是拒绝,而配置为 fail-open(故障开放)的错误仍然未知。当钩子请求批准时,单独的 owner-native 审批行仍然是权威。
插件拥有的节点操作区分 Gateway 门禁与操作结果。配对、实时连接、命令能力、插件策略和活动权限检查均会被强制执行。节点报告的成功仅为归因。如果插件策略在未调用所提供的节点回调的情况下返回,则该操作未知,且缺少 node.action_callback;OpenClaw 不会从插件结果推断出一次发送。
已附加的 worker 会将其当前凭据、bundle/版本/特性、所有者 epoch 和 turn-claim(轮次认领)准入记录为一个强制门禁。现有的 placement 和 worker-operation 记录保持权威;它们的哈希、凭据、令牌、环境 ID 和会话 ID 不会被复制到通用回执中。准入成功仅证明 worker 可以连接,而不证明后续的 worker 操作成功。
基础层在其权威生产者处记录直接本地 CLI 入口、Gateway 启动系统入口和已准入的渠道参与者。对于渠道运行,受信任的、已注册的活动原生插件产生远程参与者事实。核心只在精确记录、注册表纪元、作用域和一次性交接的情况下接受该事实;房间、路由、账户、线程、消息和传输仍然是非主体事实。boundary-verified 描述的是进程内边界验证,而不是对 Telegram、Discord 或其他远程服务的独立核心查询。收集的消息只有在每个贡献都证明同一参与者时,才保留人员身份。混合、缺失、无效、过期、重放或未铸造的证据是未知的,而明确缺乏支持的适配器是不支持的。OpenClaw 绝不会从 SenderId、From、会话密钥或路由元数据中重建参与者。插件不能公开铸造或升级参与者证据;伪造、复制、更改、过期、重用或丢失的主机载体仍然未知。
当其他公共入口的边界无法证明更具体的来源时,它们保持明确未知。直接本地执行是 unattributed(未归因):Gateway 单元、本地 CLI 入口、配置的 agent 和运行时绑定都存在,但此边界没有提供持久的调用者主体。只有当权威入口提供调用者事实时,运行才会变为 attribution-only(仅归因)。这两种状态都不意味着身份影响了允许或拒绝的决定。
配置的 webhook 映射 ID 仅标识匹配的入口来源。它们不对人员、服务或调用者进行身份验证。因此,共享的钩子身份验证和直接的 /hooks/agent 请求仍然是未归因的,除非存在另一个权威主体生产者。在准入前抑制请求的映射转换会返回其正常 HTTP 响应,但不会创建运行、执行身份、任务或决策回执。重启恢复仅在当前持久恢复所有者准入确切尝试之后,才记录系统归因。
经过身份验证的 Gateway attach 会一次性记录不可变的审计事实。会话创建会单独读取实时的规范化持久配置文件 ID,因此 attach 之后执行的配置文件链接不会使会话所有权成为孤儿。普通会话来源仅保留该 ID;它不保留配置文件显示标签。当显式启用执行身份记录时,其审计上下文还可以在敏感信息脱敏和 128 字符限制后保留准备好的显示标签。已解析的持久配置文件(包括由已验证的 trusted-proxy 或 Tailscale 身份建立的配置文件)提供假名化的人员调用者。配对设备增加设备保证,但永远不会成为人员。共享令牌、密码、无认证(auth-none)连接和其他无配置文件客户端仍然未归因。如果经过身份验证的用户证据承诺持久配置文件,但配置文件解析失败,则调用者为 unknown(未知),而不是从标头、设备 ID、连接 ID 或凭据中猜测。
Control UI 的 chat.send(包括排队回复和 ACP 轮次)会将原始准备好的 attach 事实带入执行准入。后续的配置文件更改或重新连接不会重写已准入的上下文。只有每个来源都提供等效的 attach 事实时,收集的回复才保留归因;冲突或缺失的证据仍然未知。这些事实不授予发送者或工具权限,也不会创建渠道准入强制回执。
每个当前上下文都会投影一份运行准入回执。其结果为 not-applicable,其策略和授权引用为空,其原因说明未证明任何身份感知策略或授权评估。这是对准入证据的说明,而不是强制主张。
已准入的 channel 运行在确切的 context/execution/run 元组入队后,也会投影一个 channel/admission 决策回执。仅当每个贡献的 ingress 决策都是参与者感知且影响结果时,覆盖范围才是 enforced。通配符/开放策略以及显式的仅归因适配器仍为 attribution-only;混合或缺失证据为 unknown。身份及对应决策共享现有的 audit-writer FIFO。
已准入的 session-tool 访问拒绝会通过同一 FIFO 入队一个私有 session 决策。访问所有者提供原因、策略输入和缺失证据;audit writer 在持久化前将目标 session 引用替换为安装本地 HMAC。原始 session 密钥不会被保留。改变结果的策略拒绝为 enforced,而无法提供 session.owner 证据的所有权查找仍为 unknown。公共检查有意将通用事实渲染为未验证的 decision.record;它不会暴露其私有原因或目标显示。没有确切已准入执行及其有效回执权限的调用不会创建选择器或事实。
与运行绑定的 session 工具也会在最终 await 和权限复查后入队其所有者返回的结果。create、fork、send、patch、reset、archive、restore 和 delete 事实将已提交或已计划的工作与类型化生命周期冲突以及确定性 no-op 区分开来。这些机制为 attribution-only;公共通用显示保持未验证,而不是将其私有原因或目标呈现为可信证据。
直接 session 共享方法不会准入模型运行,因此不会合成 run 选择器。共享事件在存在已验证 profile 参与者时保留它;预期但未解析的 profile 报告为 unknown,而省略的主体证据为未归因。这两种状态都不会从 operator 范围、共享 token、session 路由或 room 元数据中重建。成员列表使用相同的区分:addedBy 仅包含真实主体 id,addedByState: "unknown" 报告显式的无主体证据,省略表示未提供参与者证据。内部存储标记永远不会由 Gateway 返回。仅 Beta 的 local-operator 和 operator.admin 成员归因值作为缺失证据被丢弃;它们不会被迁移或呈现为主体。
对于启用了消息审计的已准入运行,运行检查还会适配出站消息生命周期。它会确定性地合并惰性进度所有者与终端账本行,并将 queued、platform-started、delivered、failed、unknown 以及有意 suppressed 报告为不同的回执。队列和传输结果为 attribution-only:它们记录投递所有者观察到的内容,但不证明授权。现有消息行保留其带键的目标引用和 runId;惰性伴随项保留主机验证的 context/execution/run 绑定。检查要求该确切元组,并且永远不会将仅运行的投递证据分配给执行。该绑定保持为诊断来源。只有改变结果的确切目标验证、消息策略或轮次能力拒绝才是 enforced。没有持久所有者记录的便携式操作和早期抑制使用同一 audit-writer FIFO 上的通用事实所有者。
Cron 生命周期回执为 attribution-only,并具有 not-applicable 决策结果。它们报告权威生命周期所有者保留的内容;它们不声称授权决策。游标是不透明的且特定于来源的。现有数字游标以及 a:、m: 和 g: 游标仍被接受;cron 使用 c:。格式正确的历史 t: 和 f: 游标返回 decision cursor is no longer retained; restart inspection without --cursor。它们永远不会作为其他来源的别名,也不会静默重启分页。
当同一 runId 在 operator_approvals 中保留有终端行时,检查器还会读取其所有者本地的 operator_approval_execution_identities 绑定。只有确切的 context、execution 和 run 元组才会将审批投影为 enforced。回执指明持久所有者和记录引用、确切的稳定原因代码、首次回答和终端策略引用、由允许决策创建的任何授权、使用的确切 context 字段,以及有界的下一步。它从不包含命令、参数、路径、环境、审阅者设备 id、resolver id 或审批呈现文本。
审批结果映射到稳定的回执原因:
| 记录的审批结果 | 回执原因代码 |
|---|---|
| 允许一次 / 始终允许 | operator_approval_allowed_once / operator_approval_allowed_always |
| 审阅者拒绝 | operator_approval_denied_by_reviewer |
| 截止时间过期 | operator_approval_expired |
| 运行中止 / Gateway 重启 | operator_approval_cancelled_run_aborted / operator_approval_cancelled_gateway_restart |
| 无审批投递路由 | operator_approval_denied_no_route |
| 格式错误的审批判定 | operator_approval_denied_malformed_verdict |
| 失败关闭存储状态 | operator_approval_denied_storage_corrupt |
| 不可读或不一致的行 | operator_approval_record_corrupt |
| 缺少执行绑定 | operator_approval_execution_link_missing |
| 格式错误的执行绑定 | operator_approval_execution_link_malformed |
| 记录的审批结果 | 回执原因代码 |
|---|---|
| 执行绑定不匹配 | operator_approval_execution_link_mismatch |
允许、拒绝、过期和已取消的行均为 enforced,因为记录的人工决策或 fail-closed 所有者策略改变了该操作是否可继续执行。无路由拒绝为 enforced,仅因为审批所有者在返回非操作之前,将 no-route 记录为最终生效的终态原因。不可读的行是 unknown,绝不重建。如果保留的审批指定了一个运行,但其预期执行上下文缺失,运行检查将返回 decision_context_link_missing,覆盖状态为 unknown,并且不会虚构回执上下文。
因为 runId 是关联标识而非执行身份,它绝不能替代所有者本地绑定。缺失、格式错误或绑定不匹配的行会投影为 unknown,不包含授权引用,并带有明确的绑定修复措施,即使该运行只保留了一个执行上下文。检查器绝不会从会话元数据、时间戳或保留的上下文数量推断绑定。
运行检查返回成功的类型化诊断,而不是虚构事实:
unknown:所选运行或执行未知,或预期上下文已损坏或不可读;这也包括保留的决策其预期上下文链接缺失的情况;unsupported:尽力而为的活动显示了该运行,但没有可用上下文,例如功能启用前、已禁用或上下文写入失败。刚刚超出保留期的上下文也会使用该状态,同时其有界清理仍在等待,并带有明确的过期修复措施;ambiguous:某个runId有多个保留的执行;在检查身份或决策之前,先选择一个候选executionId;unattributed:受支持的运行没有可用的调用方主体;attribution-only:存在调用方归属,但未对其进行授权评估。
该方法要求 operator.read。请求是封闭的,并且恰好选择一个 executionId 或 runId。公开结果始终包含必需的 decisionDisplays 数组,并且绝不包含私有原始回执数组或 decisions 键。Gateway 从显式的安全字段允许列表构建该结果;客户端不对回执文本进行分类。决策页面最多包含 100 个显示项;模糊运行发现页面最多包含 50 个候选执行。两者都使用有界游标。审批和消息投递选择器与其投影回执来自相同的所有者查询行元数据,使用 approval-decision: 和 message-decision: 命名空间,并且绝不派生自回执、解析或事件标识符。
同一 Gateway 操作员域中每个具有 operator.read 的客户端都可能接收此保留身份类别。这是有意为之:该范围已经覆盖日志和会话读取,收集是显式选择加入的,保留的引用是有界的且经过假名化,可选显示标签会进行机密脱敏。operator.read 不是敌对多租户隔离边界;当操作员之间不得共享此诊断数据时,请使用独立的 Gateway 信任域。
记录族¶
只要审计已启用(默认),就会记录运行和工具事件。消息生命周期事件是选择加入的,默认禁用。
| 族 | 操作 | 默认 |
|---|---|---|
| Agent 运行 | agent.run.started, agent.run.finished |
启用 |
| 工具操作 | tool.action.started, tool.action.finished |
启用 |
| 消息 | message.inbound.processed, message.outbound.{queued,platform-started,finished} |
禁用 |
每条记录都携带稳定的事件 id、单调递增的所有者序列、生命周期时间戳、actor、action、status、schemaVersion: 1 和 redaction: "metadata_only"。活动账本包含终态出站行;运行检查从其伴随组件获取非终态出站进度。有关完整字段参考和查询过滤器,请参阅 审计记录。
消息生命周期事件¶
在 设置 → 高级 → 日志 中选择消息审计元数据,或设置 logging.audit.messages。更改适用于后续的消息生命周期事件:
off(默认):不记录消息。direct:仅记录直接对话中的消息。all:记录直接、群组和频道消息。
两个权威边界会生成消息记录:
- 入站 行在已接受的消息到达核心分发时写入,包括重复和终态处理结果。
- 出站 进度记录在共享持久投递接受队列托管并开始平台投递时写入。终态活动行记录已发送、已抑制、失败,或对崩溃歧义发送的显式
unknown。包括队列恢复和死信结果。稳定的队列派生源 id 可防止恢复重复生命周期行。每个原始逻辑回复负载在每个到达的阶段获得一行;分块和适配器扇出聚合到终态resultCount。
会话类型分类¶
direct 模式是隐私边界,因此只有当目的地事实证明时,消息才会被分类为直接对话:发送路径声明了目的地会话类型,或投递会话路由准确指定了正在投递的频道和对等方。较弱的信号(例如策略状态或源会话)可以将消息分类为 group(将其排除在 direct 收集之外),但绝不能声称 direct。无法证明为直接的消息会被分类为 unknown,并且不会在 direct 模式下记录。因此,未声明聊天类型的频道在 direct 模式下记录的行可能少于在 all 模式下。
隐私模型¶
消息活动和进度记录从不存储原始平台标识符。
账户、会话、消息和目标标识符在可关联时,仅作为安装本地键控假名导出
(hmac-sha256:v1:<keyId>:<digest>):
- HMAC 密钥在首次使用时生成,按标识符类型进行域分离,并与账本位于同一状态数据库中。
- 假名在一次安装内保持稳定,因此关于同一会话的行可以关联,而不会泄露平台标识符。
- 这是关联,而非匿名化:任何对状态数据库具有读取访问权限的人也都拥有密钥,并可以针对假名测试候选原始标识符。RPC 和 CLI 导出从不包含密钥。
- 如果消息行被保留时密钥材料缺失或损坏,Gateway 会失败关闭并丢弃新的消息记录,而不是静默轮换到新密钥,后者会破坏关联。
运行和工具记录保留 sessionKey 和 sessionId 用于关联;规范会话密钥本身可能包含平台账户或对等方 ID。消息记录有意省略两者。
执行身份上下文使用相同的安装本地密钥所有者,并采用单独的 HMAC 域。原始运行时、调用方、入口来源、保证、授权和子委派引用仅存在于有界私有准入载体中。深度冻结的队列负载在每个有界证据数组中上限为 16 KiB 和 16 个条目。结构化克隆在队列边界处剥离原型。队列排空在持久化前将原始引用替换为键控假名;它们从不被存储、导出、检查或记录。已配置的代理 ID 以及上下文、执行和运行 ID 仍对操作员可见。 上下文从不包含 Prompt 或消息文本、命令主体、参数、路径、凭据、环境变量值或任意插件负载。每个编码上下文也上限为 16 KiB。
审计导出即使不包含内容,仍然是敏感的操作元数据:时间、通道、结果和稳定假名都可能关联活动。请使用与其他操作员记录相同的访问控制和保留实践来保护导出。
覆盖范围与证明限制¶
账本采用尽力而为且有意有界。应将其视为已记录内容的证据,而不是实际发生情况的证明:
- 缺少某一行不能证明任何事。 准入前的入站丢弃、绕过共享持久投递的插件本地或直发路径发送、被丢弃的准入信封以及崩溃丢失的排队工作都可能不留下记录。
- 写入通过有界的异步进程拥有队列进行;队列饱和、存储故障或有界关闭超时可能丢弃记录并记录一条操作警告。
- 关闭会在其现有截止时间丢弃等待的元数据,但在释放写入器之前会等待已提交的工作进程操作完成。未知工作进程结果不会被重放;普通原生锁竞争保留现有的 FIFO 重试。
- 崩溃歧义的出站发送记录为
unknown,而不是虚构的结果。
此账本支持调试和操作审查。它不是无损合规归档;如果需要,请使用由 OpenTelemetry 或通道级工具提供数据的外部系统。
存储、保留与迁移¶
记录位于共享状态数据库(state/openclaw.sqlite)中。现有的共享状态工作进程在 Gateway 线程之外执行审计写入和维护,包括模式/密钥首次使用以及写入触发的修剪。查询从不返回超过 30 天的记录,且账本上限为 100,000 行;过期行会在启动、每小时维护和后续写入期间被修剪。每个账本或进度清理事务最多删除 1,024 行过期行,并安排更多工作直至完成。即使收集被禁用,保留维护仍会继续运行。
出站 queued 和 platform-started 记录位于窄范围拥有的 outbound_message_progress 表中。该表仅在首次启用进度写入时幂等创建,在启动、只读检查、禁用收集和仅终态投递之后保持不存在,并且不会推进状态模式版本。在只读检查中缺失意味着没有保留的进度。它上限为 200,000 行,并采用相同的 30 天保留策略。终态 message.outbound.finished 行保留在 audit_events 中,因此兼容的旧版 Gateway 可以打开并使用数据库,同时忽略该附加表。精确的终态关联位于懒加载的 outbound_message_execution_bindings 伴随表中,而不是更改已发布的 audit_events 结构。它仅为经过主机验证的精确绑定创建;仅运行的终态写入会使其保持不存在。兼容的旧版 Gateway 也会忽略此附加表。
从具有早期仅运行/工具账本的 Gateway 升级时,模式会在启动时自动迁移(或通过 openclaw doctor --fix);现有行及其账本序列会被保留。
执行身份上下文也位于共享状态数据库中。规范行以唯一的执行和上下文 ID 作为键;runId 是非唯一、带索引的关联。其附加表在首次使用时懒加载创建,且不提升模式版本。全新和升级的安装不会填充身份上下文,直到操作员启用收集。首次使用的模式创建、HMAC 密钥访问、规范上下文构建和 SQLite 持久化都发生在进程拥有的审计队列排空中,绝不在代理准入中。锁尝试快速失败,并以有界退避异步重试,因此 SQLite 竞争不会在 Gateway 线程上同步等待。上下文保留 30 天,上限为 100,000 行。精确执行检查和运行发现在该上下文超过 30 天后从不返回上下文、候选或准入决定,即使物理清理尚未运行。过期行会在 Gateway 启动、每小时审计维护和后续上下文写入期间被修剪,每次写入或维护周期最多删除 1,024 行身份上下文行。即使收集被禁用,维护仍会继续。旧版本构建会忽略此表。
过期后立即,检查可以将该运行报告为 unsupported,而过期行仍然只能证明其身份上下文已不可用;不会返回任何过期字段或决策。在有限清理之后,如果没有单独保留的尽力而为活动仍然存在,同一查找可能变为 unknown。该转换并不能证明该运行未发生。这些限制使检查器成为运维诊断界面,而不是合规归档。
终态审批在其所有者原生的 operator_approvals 表中保留 30 天。即使物理清理尚未运行,检查也会应用该截止期限。增量式 execution_decision_facts 表专用于没有所有者原生持久记录的操作边界,包括可移植消息操作、策略拒绝以及早期有意抑制。它在首次通用事实写入时惰性创建,事实保留 30 天,表上限为 250,000 行,并且每次写入或维护周期最多清理 1,024 行。审批路径从不写入此表。其事实和审批行对其记录的决策具有权威性。向通用表投递使用有界审计队列,并在持久化之前保持尽力而为;审批所有者写入不依赖该队列。活动台账在丢失后无法重建任一来源。
每次通用决策事实写入都会重新读取不可变执行上下文,并要求完整的上下文、执行和运行元组。投影会再次验证同一元组;不匹配结果为 unknown,不会仅通过上下文或运行关联重新分配。
查询¶
Gateway 在共享状态数据库工作器上运行 audit.list 和 audit.activity.list 查询,以便 SQLite 工作不会阻塞请求处理。过滤器和保留截止期限在每次读取开始时捕获;序列游标、结果限制以及现有的 operator.read 权限保持不变。
audit.run.inspect 使用现有的只读工作器进行身份发现和回执查询。缺失的数据库和可选审计表保持不存在;检查不会迁移状态或加入审计写入器队列。每个请求在让出之前捕获其选择器、游标、限制和保留时钟。
- CLI:
openclaw audit,支持按 agent、session、run、kind、status、direction、channel、时间边界和游标分页进行过滤。 - Gateway RPC:
audit.activity.list(需要operator.read)返回版本化的 V1 活动事件联合;已发布的audit.listRPC 对旧版 run/tool 客户端保持不变。参见 Gateway 协议。 - 身份 RPC:
audit.run.inspect(需要operator.read)接受一个executionId用于精确检查,或一个runId用于有界发现。对于精确匹配,它返回不可变 V1 上下文,以及针对准入、审批、所有者原生出站消息和通用决策记录的分页安全显示;当运行具有多个执行时,返回带有空显示数组的类型化模糊候选页。原始所有者回执对聚合和存储所有者保持私有。
维护者不变量¶
对身份生产者、存储和检查的更改必须与上述操作员行为一起保留这些边界:
- 只有字节相同的规范重放是幂等的。重试、回退和恢复复用原始准入身份。
- 父审批行是唯一的授权所有者。其可选身份伴随项仅在显式收集选择加入下,为精确的主机验证源运行绑定持久化身份;禁用和未绑定路径保持该表不存在。当溯源缺失、被删除或损坏时,它不得更改审批决策。不要添加急切创建、延迟绑定、双写、回退读取器、sidecar 或模式版本变通方案。更改需要旧读取器打开/使用以及候选重开证明。
- 调用者证据是三态的:带标签且包含主体的输入为
present,带标签但不含主体的输入为unknown,仅省略为absent。在投影或字段丢弃之前验证封闭的原始变体;拒绝格式错误、混合、未标记或包含额外字段的输入,而不是对其进行规范化。 - 通用决策事实需要显式产品边界生产者和操作员保留选择加入。30 天限制不授权默认收集。生产者使用准入的共享
AuditEventWriterFIFO;切勿直接写入通用存储、创建另一个写入器/密钥,或在本地进行假名化。只有写入器在持久化之前对原始引用进行 HMAC 投影。 enforced回执覆盖是诊断性的,而非权威:仅当所有者更改了结果且精确的上下文/执行/运行元组验证通过时发出它。在等待的工作之后,在 sink 之前立即同步重新验证精确的实时所有者,中间没有 await。过期的、已释放的、被替换的或抛出异常的权威不发出回执,而不是unknown。同一运行的包装器组合所有者谓词;不同的已准入运行开始新的谓词根。决策证据不足时保持unknown。- 显示信任来自所有者持有的调用路径溯源,绝不来自回执控制的
source.owner或文本。将每个选定的所有者行或事件与其来自同一查询/页面结果的所需不透明选择器配对。切勿从私有回执、解析或事件标识符派生或重新查询选择器,也不要丢弃损坏、超大或未关联的结果。 - 准入在模式检查或普通属性读取之前,验证从描述符构建的递归拥有的、可枚举的、无访问器的数据快照。继承属性不存在;访问器从不运行。准入只能验证、约束、冻结和入队:没有同步 SQLite、模式、文件系统、HMAC 密钥或就绪工作。审计失败从不延迟或中止执行。
- 公共 Plugin SDK 入口会剥离私有恢复/准入权威,包括 JavaScript 额外属性和继承属性。
- 主机铸造的参与者证据针对已最终化的上下文和精确的插件记录/生命周期纪元一次性兑换。混合参与者只能移除发送者派生的权威;切勿扩大或擦除独立工具、授权、路由或审批权威。
- 在更改读取器范围、默认关闭的收集、保留字段、30 天截止期限、维护/行边界或模式/协议契约之前,请先询问。
相关¶
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw