# 审计报告输出模板

## 记分卡 Markdown 文件模板

文件名：`AUDIT-{YYYY-MM-DD}.md`
存放位置：被审计的 Skill 目录根目录下

---

```markdown
# Skill 审计报告

| 字段 | 值 |
|------|-----|
| Skill 名称 | {skill-name} |
| Skill 路径 | {skill-path} |
| 审计时间 | {YYYY-MM-DD HH:mm} |
| 检查深度 | L{1/2}（{静态分析 / dryRun}） |
| 审计工具版本 | better-skill-audit v{version} |

---

## 综合评分：{score} / {满分}　　{PASS ✅ / FAIL ❌}

> 满分：L1 静态 112 / L2 dryRun 115。
> 通过标准（双重判定，缺一不可）：总分 ≥ 通过线（L1/L2 dryRun 统一 **≥90**）**且** 零 ERR

---

## 🔴 ERR（必须修复，共 {n} 项）

> ⚠️ 存在任何 ERR，无论总分多高，审计结果均为 FAIL。
> 每条 ERR 必须包含**四要素**：问题描述 / 问题示例（带行号）/ 解法（完整代码）/ 影响范围。

### [{ID}] {检查项名称}（扣 {x} 分）

**① 问题描述**：{谁、在哪里、什么问题、影响什么 —— 一句话说清本质}
**② 问题示例**：`{file}` 第 {line} 行
```{lang}
{贴出具体问题代码片段，标注问题所在行}
```
**③ 解法**：
```{lang}
{给出修正后的完整代码片段，说明修改位置}
```
**④ 影响范围**：{受影响的其他 skill / 文件 / 调用方；无则写「仅本文件，无副作用」}

> ❌ 禁止只写一句话描述——读者必须能据此直接定位并修复。

---

## 🟡 WARN（建议修复，共 {n} 项）

> WARN 不影响通过/不通过，但会拉低总分，可能导致跌破通过线。
> WARN 同样建议按四要素描述（可酌情简化「影响范围」）。

### [{ID}] {检查项名称}（扣 {x} 分）

**① 问题描述**：{具体描述}
**② 问题示例**：`{file}` 第 {line} 行：`{问题代码}`
**③ 解法**：{修正建议 / 代码片段}
**④ 影响范围**：{受影响范围}

---

## 📊 各维度得分

| 维度 | 得分 | 满分 | ERR数 | WARN数 |
|------|------|------|-------|--------|
| D1 流程闭环与幂等性 | {d1} | 13 | {n} | {n} |
| D2 工具与命令规范 | {d2} | 10 | {n} | {n} |
| D3 可移植性与防御 | {d3} | 15 | {n} | {n} |
| D4 Skill 可用性规范 | {d4} | 21 | {n} | {n} |
| D5 安全与操作风险 | {d5} | 21 | {n} | {n} |
| D6 代码与文档质量 | {d6} | 31 | {n} | {n} |
| D7 依赖与体量健康度 | {d7} | 4 | {n} | {n} |
| **合计** | **{total}** | **115** | | |

---

## 🔮 修复路径预估

- 当前得分：{score} / {满分}，存在 {n} 个 ERR
- 完成所有 ERR 修复后预计得分：{estimated} / {满分}
- 预计修复后结果：{PASS ✅ / 仍需修复 WARN 才能达到通过线 ⚠️}
- 建议修复优先级：ERR（按扣分从高到低）→ 影响分数的 WARN → 其余 WARN

---

## 📋 检查项完整清单

| ID | 检查项 | 等级 | 分值 | 执行深度 | 结果 | 备注 |
|----|--------|------|------|---------|------|------|
| D1-E1 | 写操作后有结果验收 | ERR | 3 | L1 | {✅/❌/➖} | |
| D1-E2 | 写操作前检查是否已完成（幂等） | ERR | 3 | L1 | | |
| D1-E3 | 异常分支阻断流程 | ERR | 3 | L1 | | |
| D1-W1 | 流程末尾有执行摘要 | WARN | 2 | L1 | | |
| D1-W2 | 冗余操作/无效中转检测 | WARN | 2 | L1 | | |
| D2-E1 | 敏感/受控域名无裸 HTTP/browser 绕过（可配置）| ERR | 3 | L1 | | |
| D2-W1 | 动态命令拼接审查 | WARN | 3 | L1 | | |
| D2-W2 | 硬编码 URL 必须审查 | WARN | 2 | L1 | | |
| D2-W3 | 跨层命令调用追踪 | WARN | 2 | L1 | | |
| D3-E1 | 无硬编码本地绝对路径 | ERR | 3 | L1 | | |
| D3-E2 | 无硬编码环境相关固定值 | ERR | 3 | L1 | | |
| D3-E3 | 无列索引硬编码 | ERR | 3 | L1 | | |
| D3-W1 | 无多 Skill 脚本副本 | WARN | 2 | L1 | | |
| D3-W2 | 分支可达性模拟 | WARN | 2 | L2 dryRun | ➖ 跳过（dryRun项） | |
| D3-W3 | 错误提示可操作性 | WARN | 2 | L1 | | |
| D4-E1 | frontmatter 完整 | ERR | 3 | L1 | | |
| D4-E2 | description 含触发时机 | ERR | 3 | L1 | | |
| D4-E3 | 有前置条件说明 | ERR | 3 | L1 | | |
| D4-E4 | 必填参数缺失有友好提示 | ERR | 3 | L1 | | |
| D4-E5 | 打包文件规范 | ERR | 3 | L1 | | |
| D4-W1 | 目录结构规范 | WARN | 2 | L1 | | |
| D4-W2 | 高风险操作有护栏声明 | WARN | 3 | L1 | | |
| D4-W3 | 关键步骤有进度反馈 | WARN | 1 | L1 | | |
| D5-E1 | 无明文敏感凭证 | ERR | 3 | L1 | | |
| D5-E2 | 无硬编码 --yes/--force 直通 | ERR | 3 | L1 | | |
| D5-E3 | URL 中禁止硬编码凭证 | ERR | 3 | L1 | | |
| D5-W1 | 批量操作有上限保护 | WARN | 3 | L1 | | |
| D5-W2 | 写操作前必须有确认环节 | WARN | 3 | L1 | | |
| D5-W3 | 配置文件明文凭证扫描 | WARN | 3 | L1 | | |
| D5-W4 | HTTP 批量写操作审查 | WARN | 3 | L1 | | |
| D6-E1 | 脚本语法正确 | ERR | 3 | L1 | | |
| D6-E2 | 逻辑完整性无缺陷 | ERR | 3 | L1 | | |
| D6-E3 | 关键边界已处理 | ERR | 3 | L1 | | |
| D6-E4 | 描述与实现一致 | ERR | 3 | L1 | | |
| D6-E5 | SKILL.md 引用必须文件路径存在 | ERR | 3 | L1 | | |
| D6-E6 | 跨表/跨源字段格式兼容性 | ERR | 3 | L1 | | |
| D6-E7 | 关键列解析后做格式校验 | WARN | 3 | L1 | | |
| D6-W1 | 代码完整性（无占位/TODO） | WARN | 2 | L1 | | |
| D6-W2 | 依赖工具版本有声明 | WARN | 2 | L1 | | |
| D6-W3 | SKILL.md 引用非必须文件路径缺失 | WARN | 3 | L1 | | |
| D6-W4 | 大代码量缺测试覆盖 | WARN | 3 | L1 | | |
| D7-W1 | Hub 已发布 | WARN | 1 | L2 dryRun | ➖ 跳过（dryRun项） | |
| D7-W2 | 依赖 Skill 清单+归属+存在性 | WARN | 2 | L1提取+L2存在性 | | |
| D7-W3 | Skill 体量合理 | WARN | 1 | L1 | | |
```

---

## 🧩 误报与漏报说明

> 本章节用于提升审计透明度，让 Skill 作者了解工具的局限性。

### 误报（False Positive）— 规则触发但实际合规

| 可能触发规则 | 常见误报场景 | 如何申诉 |
|------------|------------|---------|
| D5-E2 硬编码 `--yes` | 全自动化编排脚本，无 TTY 无法交互确认 | SKILL.md 中补充自动化声明，参考 D5-E2 例外说明 |
| D1-W1 无执行摘要 | 单步工具类 Skill（非批量处理流程） | 在 SKILL.md 中注明 Skill 类型为「工具类/查询类」 |
| D5-W1 无批量上限 | SKILL.md 或编排层已有护栏声明 | 确认护栏声明覆盖了 D5-W1 的四类判据之一 |
| D6-E4 描述与实现不一致 | 步骤描述使用了非常规同义词（如「回写」对应 update） | 在 SKILL.md 中补充同义词备注，或让代码命名与步骤一致 |
| D7-W2 import 误判为外部依赖 | 本 skill 内部模块/函数被当成外部 skill | 走「三步联立」算法第①步反查本 skill 内即可排除 |

### 漏报（False Negative）— 规则未触发但实际存在问题

| 漏报场景 | 原因 | 建议 |
|---------|------|------|
| 动态拼接的高危命令（`cmd = "tool " + user_input`） | 字符串拼接绕过静态模式扫描 | D2-W1 可部分覆盖；代码审查时人工检查动态命令拼接 |
| 间接调用（subprocess.Popen 调 shell，脚本内再调其他工具） | 跨层调用，静态扫描无法追踪 | D2-W3 + L2 分支可达性模拟可补充部分，或人工审查 Shell 脚本嵌套 |
| 软编码凭证（Token 存在同目录 `config.json` 明文） | D5-E1 只扫脚本赋值语句 | D5-W3 已覆盖配置文件扫描 |

> **总结**：静态分析有固有局限。L2 dryRun 通过只读查询与分支可达性模拟可补充部分漏报；复杂 Skill 建议在 WARN 项上做人工复核，尤其是涉及写操作的核心链路。

---

## 🔧 五、修复建议板块（报告末尾，支持一键修复）

> 报告末尾固定输出本板块，把所有问题按「能否自动修复」分两小节。每项沿用上方四要素。
> 板块结尾必须提醒用户：回复「修复」可启动一键修复（详见 SKILL.md「一键修复（`--fix`）行为规范」）。

```markdown
## 🔧 修复建议

本次共 {N+M} 项可修复问题，已按能否自动修复分类。
⚠️ 一键修复会修改被审计 skill 文件，启动前会自动备份整个 skill 目录并告知备份路径。

### 5.1 ✅ 可一键修复（{N} 项，纯文本/配置/文档类，无业务逻辑风险）

适用：补 frontmatter version、补前置条件说明、补护栏声明、改文案、补依赖声明、规范目录引用前缀等。

#### [{ID}] {检查项名称}
- **① 问题描述**：{...}
- **② 问题示例**：`{file}` 第 {line} 行：`{当前内容}`
- **③ 解法**：`{修改后内容}`
- **④ 影响范围**：仅 {file}，无业务逻辑副作用

### 5.2 ⚠️ 需人工确认（{M} 项，涉及业务逻辑/脚本代码，需人工 review）

适用：改脚本控制流、字段匹配逻辑、HTTP 调用方式、列名映射、越权步骤移除等。

#### [{ID}] {检查项名称}
- **① 问题描述**：{...}
- **② 问题示例**：`{file}` 第 {line} 行（贴代码片段）
- **③ 解法**：{完整修正代码片段}
- **④ 影响范围**：{受影响 skill/文件/调用方}
- ⚠️ **需人工确认原因**：{涉及业务逻辑，自动改可能引入回归，需开发 review + 测试}

---

> 💡 回复「修复」启动一键修复（仅处理 5.1）；5.2 各项需你逐条确认后我才会改。
> 修复前我会自动备份 skill 目录，修复后会提醒你是否重新审计。
```

---

## 📦 六、Skill 依赖章节（报告固定章节）

> 报告固定输出本章节，明确写清被审 skill **依赖了哪些 skill、依赖它们做什么、是否已安装**。
> 无论依赖几个（哪怕 0 个）都要输出本章节；0 个时写「✅ 本 skill 无外部 skill 依赖」。

```markdown
## 📦 Skill 依赖

本 skill 依赖以下 {n} 个外部 skill：

| 依赖 skill | 依赖它做什么 | 引用方式 | 状态 |
|-----------|------------|---------|------|
| some-skill | {用途} | subprocess 调 xxx.sh | 本地已装 ✅ |
| other-skill | {用途} | from xxx import yyy | Hub 有未装 ⚠️ |
| missing-skill | {用途} | {import / subprocess / CLI} | 找不到 ❌ |

**状态说明**：
- ✅ 本地已装：`~/.openclaw/workspace/skills/<dep>/` 存在
- ⚠️ Hub 有未装：本地无，但 Hub 可查到
- ❌ 找不到：本地无 + Hub 查不到 → **ERR**，需人工排查（依赖名拼错？私有 skill？已下线？）
```
