周三下午三点,你的工程师用Claude Code执行了一条Bash命令。三个月后审计员上门,你能准确说出那条命令是什么、操作了哪个仓库、返回码是多少吗?

大多数团队做不到。Claude Code官方文档用两段话带过了PostToolUse钩子,但生产环境的合规审计需要的不只是"能跑起来"的代码。

打开网易新闻 查看精彩图片

这是Claude Code生命周期钩子的另一半。PreToolUse是闸门——决定AI能做什么;PostToolUse是记录仪——记录AI实际做了什么。两者共享同样的数据格式,回答的问题截然不同:"这件事该不该发生" versus "这件事已经发生了什么"。

打开网易新闻 查看精彩图片

对于SOC 2 CC6.1和CC7.2这类访问日志与系统监控控制项,后者才是关键。这些条款要求的是回溯性证据:"展示过去90天内你的特权操作员执行了哪些操作"。Claude Code在agentic模式下,按任何合理的解读都是运行在工程师机器上的特权操作员。告诉审计员"我们会查模型的会话记录",这种回答行不通。

以下是我们部署到Claude Code Max环境中的核心审计钩子,针对过去几个月相邻钩子代码中出现的故障模式设计:

#!/usr/bin/env bash
# PostToolUse: append every tool call as a JSON line.
set -uo pipefail
INPUT=$(cat)
[ -z "$INPUT" ] && exit 0
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // "unknown"')
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
EXIT_CODE=$(echo "$INPUT" | jq -r '.tool_response.exit_code // 0')
mkdir -p ~/.claude/audit
jq -nc \
--arg ts "$TS" --arg tool "$TOOL" --arg command "$CMD" \
--argjson exit "$EXIT_CODE" \
'{ts: $ts, tool: $tool, command: $command, exit_code: $exit}' \
>> ~/.claude/audit/$(date -u +%Y-%m-%d).jsonl
exit 0

打开网易新闻 查看精彩图片

时间戳采用UTC ISO-8601格式——六周后读日志时,没人想猜时区。工具名、命令内容、退出码全部结构化存储。每天一个JSONL文件,追加写入而非覆盖,这是审计日志的底线要求。

这个钩子的设计前提只有一个:PostToolUse只能做记录。忘记这一点,它就会从审计资产变成 liabilities。调用已经执行完毕,你无法阻止任何事,只能确保事后可追溯。