openclaw-secret-scanning-maintainer
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOpenClaw Secret Scanning Maintainer
OpenClaw Secret Scanning 维护者指南
Maintainer-only. This skill requires repo admin / maintainer permissions to edit or delete other users' comments and resolve secret scanning alerts.
Use this skill when processing alerts from .
https://github.com/openclaw/openclaw/security/secret-scanningLanguage rule: All notification comments and replacement comments MUST be written in English.
仅限维护者使用。本技能需要仓库管理员/维护者权限,才能编辑或删除其他用户的评论并解决秘密扫描警报。
处理中的警报时,请使用本技能。
https://github.com/openclaw/openclaw/security/secret-scanning语言规则: 所有通知评论和替换评论必须使用英文撰写。
Script
脚本
All mechanical operations (API calls, temp file management, security enforcements) are handled by:
$REPO_ROOT/.agents/skills/openclaw-secret-scanning-maintainer/scripts/secret-scanning.mjsThe script enforces:
- on all alert fetches (no plaintext secrets in stdout)
hide_secret=true - with random UUIDs for all temp files
mktemp - for all body uploads (no inline shell quoting)
-F body=@file - Notification templates branched by location type
- Never prints or
.secretto stdout.body
所有机械操作(API调用、临时文件管理、安全强制规则)均由以下脚本处理:
$REPO_ROOT/.agents/skills/openclaw-secret-scanning-maintainer/scripts/secret-scanning.mjs该脚本强制执行以下规则:
- 所有警报获取操作启用(标准输出中不会出现明文密钥)
hide_secret=true - 所有临时文件使用随机UUID通过创建
mktemp - 所有内容上传使用(避免内联shell引用问题)
-F body=@file - 根据位置类型分支使用不同的通知模板
- 绝不会将或
.secret内容打印到标准输出.body
Overall Flow
整体流程
Supports single or multiple alerts. For multiple alerts, process in ascending order.
For each alert:
- Identify — +
fetch-alertto get metadata and bodyfetch-content - Decide — Agent reads the body file, identifies all secrets, produces redacted version
- Redact — for issue/PR body; skip for comments (delete directly)
redact-body - Purge — +
delete-commentfor comments; cannot purge body historyrecreate-comment - Notify — posts the right template per location type
notify - Resolve — closes the alert
resolve - Summary — prints formatted results
summary
支持处理单个或多个警报。若为多个警报,请按升序处理。
针对每个警报,执行以下步骤:
- 识别 — 执行+
fetch-alert获取元数据和内容fetch-content - 决策 — Agent读取内容文件,识别所有密钥,生成脱敏版本
- 脱敏 — 对议题/PR正文执行;评论直接跳过(直接删除)
redact-body - 清除 — 对评论执行+
delete-comment;无法清除正文编辑历史recreate-comment - 通知 — 执行,根据位置类型发布对应模板
notify - 解决 — 执行关闭警报
resolve - 汇总 — 执行打印格式化结果
summary
Step 1: Identify
步骤1:识别
bash
undefinedbash
undefinedList all open alerts
列出所有未处理的警报
node secret-scanning.mjs list-open
node secret-scanning.mjs list-open
Fetch specific alert metadata + locations
获取指定警报的元数据和位置信息
node secret-scanning.mjs fetch-alert <NUMBER>
node secret-scanning.mjs fetch-alert <NUMBER>
Fetch content for each location (saves body to temp file)
获取每个位置的内容(将正文保存到临时文件)
node secret-scanning.mjs fetch-content '<location-json>'
The `fetch-content` output includes:
- `body_file`: path to temp file with full body content
- `author`: who posted it
- `issue_number` / `pr_number`: where it is
- `edit_history_count`: number of existing edits
- `type`: location type for routing
- For `discussion_comment`, it also includes `comment_node_id`, `discussion_node_id`, and `reply_to_node_id` when the original comment was a reply.node secret-scanning.mjs fetch-content '<location-json>'
`fetch-content`的输出包含:
- `body_file`:存储完整正文内容的临时文件路径
- `author`:内容发布者
- `issue_number` / `pr_number`:内容所在的议题/PR编号
- `edit_history_count`:已有的编辑次数
- `type`:用于路由的位置类型
- 对于`discussion_comment`,还包含`comment_node_id`、`discussion_node_id`,若原评论为回复,则额外包含`reply_to_node_id`Location type routing
位置类型路由
| type | Flow |
|---|---|
| Comment: delete+recreate |
| Comment: delete+recreate |
| Comment: delete+recreate |
| Discussion comment: delete+recreate (GraphQL) |
| Body: redact in place |
| Body: redact in place |
| Notify only |
| other | Skip and report |
| 类型 | 流程 |
|---|---|
| 评论:删除+重新创建 |
| 评论:删除+重新创建 |
| 评论:删除+重新创建 |
| 讨论评论:删除+重新创建(使用GraphQL) |
| 正文:原地脱敏 |
| 正文:原地脱敏 |
| 仅发送通知 |
| 其他 | 跳过并在汇总中报告 |
Step 2: Decide (Agent)
步骤2:决策(Agent)
The agent reads the body file from output and:
fetch-content- Identifies ALL secrets in the content (there may be more than the alert flagged)
- Replaces each secret with — no partial values, no prefix/suffix
[REDACTED <secret_type>] - Saves the redacted content to a new temp file
This is the only step that requires semantic understanding. Everything else is mechanical.
Agent读取输出中的正文文件,并执行以下操作:
fetch-content- 识别内容中的所有密钥(可能超出警报标记的范围)
- 将每个密钥替换为—— 不保留部分值,不保留前缀/后缀
[REDACTED <secret_type>] - 将脱敏后的内容保存到新的临时文件
这是唯一需要语义理解的步骤,其余步骤均为机械操作。
Step 3: Redact
步骤3:脱敏
For comments (issue_comment / PR comments)
针对评论(issue_comment / PR评论)
Do NOT redact. Skip directly to Step 4 (delete + recreate). PATCHing before DELETE creates an unnecessary edit history revision.
请勿脱敏。直接跳至步骤4(删除 + 重新创建)。在删除前执行PATCH操作会生成不必要的编辑历史版本。
For issue_body / pull_request_body
针对issue_body / pull_request_body
bash
node secret-scanning.mjs redact-body <issue|pr> <NUMBER> <redacted-body-file>bash
node secret-scanning.mjs redact-body <issue|pr> <NUMBER> <redacted-body-file>Step 4: Purge Edit History
步骤4:清除编辑历史
Comments — Delete and Recreate
评论 —— 删除并重新创建
For issue/PR comments:
bash
undefined针对议题/PR评论:
bash
undefinedDelete original (all edit history gone)
删除原评论(所有编辑历史将被清除)
node secret-scanning.mjs delete-comment <COMMENT_ID>
node secret-scanning.mjs delete-comment <COMMENT_ID>
Recreate with redacted content
使用脱敏内容重新创建评论
node secret-scanning.mjs recreate-comment <ISSUE_NUMBER> <body-file>
For discussion comments (uses GraphQL):
```bashnode secret-scanning.mjs recreate-comment <ISSUE_NUMBER> <body-file>
针对讨论评论(使用GraphQL):
```bashDelete original
删除原评论
node secret-scanning.mjs delete-discussion-comment <COMMENT_NODE_ID>
node secret-scanning.mjs delete-discussion-comment <COMMENT_NODE_ID>
Recreate with redacted content
使用脱敏内容重新创建评论
node secret-scanning.mjs recreate-discussion-comment <DISCUSSION_NODE_ID> <body-file> [REPLY_TO_NODE_ID]
The `fetch-content` output for `discussion_comment` includes `comment_node_id` and `discussion_node_id` for these commands. When the original discussion comment was a reply, it also includes `reply_to_node_id`; pass that optional third argument so the redacted replacement stays in the original thread.
The recreated comment should follow this format:
Note: The original comment by @<AUTHOR> has been removed due to secret leakage. Below is the redacted version of the original content.
<redacted original content> ```
node secret-scanning.mjs recreate-discussion-comment <DISCUSSION_NODE_ID> <body-file> [REPLY_TO_NODE_ID]
`fetch-content`针对`discussion_comment`的输出包含`comment_node_id`和`discussion_node_id`,用于上述命令。若原讨论评论为回复,则还包含`reply_to_node_id`;传递该可选第三个参数可确保脱敏后的评论保留在原线程中。
重新创建的评论应遵循以下格式:
注意: @<AUTHOR>发布的原评论因密钥泄露已被移除。以下是原内容的脱敏版本。
<脱敏后的原内容>
undefinedissue_body / pull_request_body — Cannot Purge
issue_body / pull_request_body —— 无法清除
Editing creates an edit history revision with the pre-edit plaintext. This cannot be cleared via API.
Output to maintainer terminal only (never in public comments):
⚠️ Issue/PR body edit history still contains plaintext secrets.
Contact GitHub Support to purge: https://support.github.com/contact
Request purge of issue/PR #{NUMBER} userContentEdits.CRITICAL: Do NOT mention edit history or the "edited" button in any public comment or resolution_comment.
编辑操作会生成包含编辑前明文的历史版本,无法通过API清除。
仅输出到维护者终端(绝不能出现在公开评论中):
⚠️ 议题/PR正文的编辑历史仍包含明文密钥。
请联系GitHub Support清除:https://support.github.com/contact
请求清除议题/PR #{NUMBER}的userContentEdits。重要提示: 请勿在任何公开评论或解决评论中提及编辑历史、“已编辑”按钮或提交SHA。
Commits
提交(Commits)
Cannot clean. Notify author to delete branch or force-push (for unmerged PRs).
无法清理。通知作者删除分支或强制推送(针对未合并的PR)。
Step 5: Notify
步骤5:通知
bash
node secret-scanning.mjs notify <TARGET> <AUTHOR> <LOCATION_TYPE> <SECRET_TYPES> [REPLY_TO_NODE_ID]- For non-discussion types, is the issue/PR number.
<TARGET> - For ,
discussion_commentis the<TARGET>returned bydiscussion_node_id.fetch-content - For reply-style locations, pass the optional
discussion_commentfromreply_to_node_idso the notification stays in the same thread.fetch-content
Secret types are comma-separated:
"Discord Bot Token,Feishu App Secret"The script picks the right template:
- comment types: "your comment … removed and replaced"
- body types: "your issue/PR description … redacted in place"
- commit: "code you committed"
bash
node secret-scanning.mjs notify <TARGET> <AUTHOR> <LOCATION_TYPE> <SECRET_TYPES> [REPLY_TO_NODE_ID]- 对于非讨论类型,为议题/PR编号。
<TARGET> - 对于,
discussion_comment为<TARGET>返回的fetch-content。discussion_node_id - 对于回复类型的位置,传递
discussion_comment返回的可选fetch-content,确保通知保留在同一线程中。reply_to_node_id
密钥类型以逗号分隔:
"Discord Bot Token,Feishu App Secret"脚本会自动选择对应模板:
- 评论类型:“你的评论已被移除并替换”
- 正文类型:“你的议题/PR描述已原地脱敏”
- 提交:“你提交的代码”
Step 6: Resolve
步骤6:解决
bash
node secret-scanning.mjs resolve <ALERT_NUMBER>bash
node secret-scanning.mjs resolve <ALERT_NUMBER>or with custom resolution:
或使用自定义解决方式:
node secret-scanning.mjs resolve <ALERT_NUMBER> revoked "Custom comment"
Resolution is `revoked` by default. As maintainers we cannot control whether users rotate — our responsibility is to redact + notify. The `revoked` means "this secret should be considered leaked", not "I confirmed it was revoked".node secret-scanning.mjs resolve <ALERT_NUMBER> revoked "Custom comment"
默认解决方式为`revoked`。作为维护者,我们无法控制用户是否轮换密钥——我们的职责是脱敏+通知。`revoked`表示“该密钥应被视为已泄露”,而非“我确认密钥已被撤销”。Step 7: Summary
步骤7:汇总
After processing, create a JSON results file and pass it to the summary command:
bash
node secret-scanning.mjs summary /tmp/results.jsonThe script outputs a block delimited by and . You MUST output the content between these markers verbatim to the user. Do NOT rephrase, reformat, abbreviate, or create your own summary. The script already includes full URLs for every alert and location.
---BEGIN SUMMARY------END SUMMARY---The JSON format:
json
[
{
"number": 72,
"secret_type": "Discord Bot Token",
"location_label": "Issue #63101 comment",
"location_url": "https://github.com/openclaw/openclaw/issues/63101#issuecomment-xxx",
"actions": "Deleted+Recreated+Notified",
"history_cleared": true
}
]For unsupported types, add .
"skipped": true, "unsupported_type": "<type>"处理完成后,创建JSON结果文件并传递给汇总命令:
bash
node secret-scanning.mjs summary /tmp/results.json脚本会输出以和分隔的内容。你必须将这些标记之间的内容原封不动地输出给用户,不得改写、重新格式化、缩写或自行创建汇总内容。 脚本已包含每个警报和位置的完整URL。
---BEGIN SUMMARY------END SUMMARY---JSON格式如下:
json
[
{
"number": 72,
"secret_type": "Discord Bot Token",
"location_label": "Issue #63101 comment",
"location_url": "https://github.com/openclaw/openclaw/issues/63101#issuecomment-xxx",
"actions": "Deleted+Recreated+Notified",
"history_cleared": true
}
]对于不支持的类型,添加。
"skipped": true, "unsupported_type": "<type>"Safety Rules
安全规则
- Agent reads content, identifies secrets, produces redaction. Script handles all API calls.
- Never include any portion of a secret in public comments, redaction markers, or terminal output.
- Never include alert URLs or numbers in public comments.
- For comments, skip PATCH — go directly to DELETE + recreate.
- Never mention edit history, "edited" button, or commit SHAs in any public content.
- Ask for confirmation before deleting any comment.
- One alert at a time unless user requests batch.
- All public comments in English.
- Skip unsupported location types and report in summary.
- Agent负责读取内容、识别密钥、生成脱敏版本。脚本处理所有API调用。
- 绝不能在公开评论、脱敏标记或终端输出中包含任何密钥片段。
- 绝不能在公开评论中包含警报URL或编号。
- 对于评论,跳过PATCH操作——直接执行DELETE + 重新创建。
- 绝不能在任何公开内容中提及编辑历史、“已编辑”按钮或提交SHA。
- 删除任何评论前需确认。
- 除非用户要求批量处理,否则一次处理一个警报。
- 所有公开评论必须使用英文。
- 跳过不支持的位置类型并在汇总中报告。