openclaw-secret-scanning-maintainer

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OpenClaw 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-scanning
.
Language 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.mjs
The script enforces:
  • hide_secret=true
    on all alert fetches (no plaintext secrets in stdout)
  • mktemp
    with random UUIDs for all temp files
  • -F body=@file
    for all body uploads (no inline shell quoting)
  • Notification templates branched by location type
  • Never prints
    .secret
    or
    .body
    to stdout
所有机械操作(API调用、临时文件管理、安全强制规则)均由以下脚本处理:
$REPO_ROOT/.agents/skills/openclaw-secret-scanning-maintainer/scripts/secret-scanning.mjs
该脚本强制执行以下规则:
  • 所有警报获取操作启用
    hide_secret=true
    (标准输出中不会出现明文密钥)
  • 所有临时文件使用随机UUID通过
    mktemp
    创建
  • 所有内容上传使用
    -F body=@file
    (避免内联shell引用问题)
  • 根据位置类型分支使用不同的通知模板
  • 绝不会将
    .secret
    .body
    内容打印到标准输出

Overall Flow

整体流程

Supports single or multiple alerts. For multiple alerts, process in ascending order.
For each alert:
  1. Identify
    fetch-alert
    +
    fetch-content
    to get metadata and body
  2. Decide — Agent reads the body file, identifies all secrets, produces redacted version
  3. Redact
    redact-body
    for issue/PR body; skip for comments (delete directly)
  4. Purge
    delete-comment
    +
    recreate-comment
    for comments; cannot purge body history
  5. Notify
    notify
    posts the right template per location type
  6. Resolve
    resolve
    closes the alert
  7. Summary
    summary
    prints formatted results
支持处理单个或多个警报。若为多个警报,请按升序处理。
针对每个警报,执行以下步骤:
  1. 识别 — 执行
    fetch-alert
    +
    fetch-content
    获取元数据和内容
  2. 决策 — Agent读取内容文件,识别所有密钥,生成脱敏版本
  3. 脱敏 — 对议题/PR正文执行
    redact-body
    ;评论直接跳过(直接删除)
  4. 清除 — 对评论执行
    delete-comment
    +
    recreate-comment
    ;无法清除正文编辑历史
  5. 通知 — 执行
    notify
    ,根据位置类型发布对应模板
  6. 解决 — 执行
    resolve
    关闭警报
  7. 汇总 — 执行
    summary
    打印格式化结果

Step 1: Identify

步骤1:识别

bash
undefined
bash
undefined

List 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

位置类型路由

typeFlow
issue_comment
Comment: delete+recreate
pull_request_comment
Comment: delete+recreate
pull_request_review_comment
Comment: delete+recreate
discussion_comment
Discussion comment: delete+recreate (GraphQL)
issue_body
Body: redact in place
pull_request_body
Body: redact in place
commit
Notify only
otherSkip and report
类型流程
issue_comment
评论:删除+重新创建
pull_request_comment
评论:删除+重新创建
pull_request_review_comment
评论:删除+重新创建
discussion_comment
讨论评论:删除+重新创建(使用GraphQL)
issue_body
正文:原地脱敏
pull_request_body
正文:原地脱敏
commit
仅发送通知
其他跳过并在汇总中报告

Step 2: Decide (Agent)

步骤2:决策(Agent)

The agent reads the body file from
fetch-content
output and:
  1. Identifies ALL secrets in the content (there may be more than the alert flagged)
  2. Replaces each secret with
    [REDACTED <secret_type>]
    no partial values, no prefix/suffix
  3. 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
输出中的正文文件,并执行以下操作:
  1. 识别内容中的所有密钥(可能超出警报标记的范围)
  2. 将每个密钥替换为
    [REDACTED <secret_type>]
    —— 不保留部分值,不保留前缀/后缀
  3. 将脱敏后的内容保存到新的临时文件
这是唯一需要语义理解的步骤,其余步骤均为机械操作。

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
undefined

Delete 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):

```bash
node secret-scanning.mjs recreate-comment <ISSUE_NUMBER> <body-file>

针对讨论评论(使用GraphQL):

```bash

Delete 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>发布的原评论因密钥泄露已被移除。以下是原内容的脱敏版本。

<脱敏后的原内容>
undefined

issue_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,
    <TARGET>
    is the issue/PR number.
  • For
    discussion_comment
    ,
    <TARGET>
    is the
    discussion_node_id
    returned by
    fetch-content
    .
  • For reply-style
    discussion_comment
    locations, pass the optional
    reply_to_node_id
    from
    fetch-content
    so the notification stays in the same thread.
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]
  • 对于非讨论类型,
    <TARGET>
    为议题/PR编号。
  • 对于
    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.json
The script outputs a block delimited by
---BEGIN SUMMARY---
and
---END SUMMARY---
. 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.
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
脚本会输出以
---BEGIN SUMMARY---
---END SUMMARY---
分隔的内容。你必须将这些标记之间的内容原封不动地输出给用户,不得改写、重新格式化、缩写或自行创建汇总内容。 脚本已包含每个警报和位置的完整URL。
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
  • 删除任何评论前需确认
  • 除非用户要求批量处理,否则一次处理一个警报
  • 所有公开评论必须使用英文
  • 跳过不支持的位置类型并在汇总中报告。