OpenClaw Secret Scanning Maintainer
Apenas para mantenedores. Esta habilidade requer permissões de admin/mantenedor do repositório para editar ou excluir comentários de outros usuários e resolver alertas de varredura de segredos.
Use esta habilidade ao processar alertas de https://github.com/openclaw/openclaw/security/secret-scanning.
Regra de idioma: Todos os comentários de notificação e comentários de substituição DEVEM ser escritos em inglês.
Script
Todas as operações mecânicas (chamadas de API, gerenciamento de arquivos temporários, aplicação de segurança) são tratadas por:
$REPO_ROOT/.agents/skills/openclaw-secret-scanning-maintainer/scripts/secret-scanning.mjs
O script impõe:
hide_secret=trueem todas as buscas de alerta (sem segredos em texto puro no stdout)mktempcom UUIDs aleatórios para todos os arquivos temporários-F body=@filepara todos os uploads de corpo (sem citação inline em shell)- Modelos de notificação ramificados por tipo de localização
- Nunca imprime
.secretou.bodyno stdout
Fluxo Geral
Suporta um único alerta ou múltiplos alertas. Para múltiplos alertas, processe em ordem crescente.
Para cada alerta:
- Identificar —
fetch-alert+fetch-contentpara obter metadados e corpo - Decidir — O agente lê o arquivo de corpo, identifica se ainda há segredos em texto puro e produz uma versão redigida apenas quando necessário
- Redigir —
redact-body-if-neededpara corpo de issue/PR; pular para comentários (deletar diretamente) - Limpar —
delete-comment+recreate-commentpara comentários; não é possível limpar histórico de edições do corpo - Notificar —
notifypublica o modelo correto por tipo de localização, a menos que o corpo atual da issue/PR já esteja redigido - Resolver —
resolvefecha o alerta - Sumário —
summaryimprime resultados formatados
Passo 1: Identificar
# Listar todos os alertas abertos
node secret-scanning.mjs list-open
# Buscar metadados + localizações de um alerta específico
node secret-scanning.mjs fetch-alert <NUMERO>
# Buscar conteúdo de cada localização (salva o corpo em um arquivo temporário)
node secret-scanning.mjs fetch-content '<localizacao-json>'
A saída de fetch-content inclui:
body_file: caminho para o arquivo temporário com o conteúdo completo do corpoauthor: quem publicouissue_number/pr_number: onde estáedit_history_count: número de edições existentestype: tipo de localização para roteamento- Para
discussion_comment, também incluicomment_node_id,discussion_node_idereply_to_node_idquando o comentário original era uma resposta.
Roteamento por tipo de localização
| type | Fluxo |
|---|---|
issue_comment | Comentário: deletar+recriar |
pull_request_comment | Comentário: deletar+recriar |
pull_request_review_comment | Comentário: deletar+recriar |
discussion_comment | Comentário de discussão: deletar+recriar (GraphQL) |
issue_body | Corpo: redigir no local |
pull_request_body | Corpo: redigir no local |
commit | Apenas notificar |
| outro | Pular e relatar |
Passo 2: Decidir (Agente)
O agente lê o arquivo de corpo da saída de fetch-content e:
- Identifica TODOS os segredos no conteúdo (pode haver mais do que o alerta sinalizou)
- Determina se ainda resta alguma credencial em texto puro no corpo atual
- Substitui cada segredo restante por
[REDACTED <tipo_do_segredo>]— sem valores parciais, sem prefixo/sufixo - Salva o conteúdo redigido em um novo arquivo temporário
Esta é a única etapa que requer compreensão semântica. Todo o resto é mecânico.
Para issue_body e pull_request_body: se o corpo atual já foi redigido pelo autor e nenhuma credencial em texto puro permanece, não publique um comentário público de notificação. Isso evita criar um novo ponteiro público para conteúdo histórico sensível. Registre essa redação separadamente e use o Passo 6 para decidir se a evidência suporta a resolução do alerta.
Passo 3: Redigir
Para comentários (issue_comment / comentários de PR)
NÃO redigir. Pule diretamente para o Passo 4 (deletar + recriar). Usar PATCH antes de DELETE cria uma revisão desnecessária no histórico de edições.
Para issue_body / pull_request_body
node secret-scanning.mjs redact-body-if-needed <issue|pr> <NUMERO> <arquivo-corpo-atual> <arquivo-corpo-redigido> <arquivo-resultado>
Use o body_file de fetch-content como <arquivo-corpo-atual>. O comando escreve notify_required no <arquivo-resultado> e só aplica PATCH no corpo quando o arquivo redigido difere do corpo atual.
Passo 4: Limpar Histórico de Edições
Comentários — Deletar e Recriar
Para comentários de issue/PR:
# Deletar original (todo histórico de edições desaparece)
node secret-scanning.mjs delete-comment <ID_DO_COMENTARIO>
# Recriar com conteúdo redigido
node secret-scanning.mjs recreate-comment <NUMERO_DA_ISSUE> <arquivo-corpo>
Para comentários de discussão (usa GraphQL):
# Deletar original
node secret-scanning.mjs delete-discussion-comment <ID_DO_NO_DO_COMENTARIO>
# Recriar com conteúdo redigido
node secret-scanning.mjs recreate-discussion-comment <ID_DO_NO_DA_DISCUSSAO> <arquivo-corpo> [ID_DO_NO_DE_RESPOSTA]
A saída de fetch-content para discussion_comment inclui comment_node_id e discussion_node_id para esses comandos. Quando o comentário original da discussão era uma resposta, também inclui reply_to_node_id; passe esse argumento opcional para que a substituição redigida permaneça no tópico original.
O comentário recriado deve seguir este formato:
> **Nota:** O comentário original de @<AUTOR> foi removido devido a vazamento de segredo. Abaixo está a versão redigida do conteúdo original.
---
<conteúdo original redigido>
issue_body / pull_request_body — Não é possível limpar histórico de edições
Editar cria uma revisão no histórico de edições com o texto puro anterior. Isso não pode ser limpo via API.
Não oriente autores publicamente a deletar/recriar issues ou fechar/reabrir PRs. Isso pode chamar atenção para conteúdo histórico. Mantenha a orientação de limpeza apenas para mantenedores.
Saída apenas no terminal do mantenedor (nunca em comentários públicos):
⚠️ O histórico de edições do corpo da issue/PR ainda contém segredos em texto puro.
Entre em contato com o Suporte do GitHub para limpar: https://support.github.com/contact
Solicite a limpeza das userContentEdits da issue/PR #{NUMERO}.
CRÍTICO: Não mencione o histórico de edições ou o botão "editado" em nenhum comentário público ou comentário de resolução.
Commits
Não é possível limpar. Notifique o autor para deletar o branch ou fazer force push (para PRs não mesclados).
Passo 5: Notificar
node secret-scanning.mjs notify <ALVO> <AUTOR> <TIPO_DE_LOCALIZACAO> <TIPOS_DE_SEGREDO> [ID_DO_NO_DE_RESPOSTA|ARQUIVO_RESULTADO_DA_REDACAO_DO_CORPO]
- Para tipos que não são de discussão,
<ALVO>é o número da issue/PR. - Para
discussion_comment,<ALVO>é odiscussion_node_idretornado porfetch-content. - Para localizações de
discussion_commentdo tipo resposta, passe oreply_to_node_idopcional defetch-contentpara que a notificação permaneça no mesmo tópico. - Para
issue_bodyepull_request_body, passe o<arquivo-resultado>deredact-body-if-needed. O script pula a notificação quandonotify_requiredéfalsee recusa notificações de corpo sem este arquivo.
Os tipos de segredo são separados por vírgula: "Discord Bot Token,Feishu App Secret"
O script escolhe o modelo correto:
- tipos de comentário: "seu comentário … removido e substituído"
- tipos de corpo: "sua descrição de issue/PR … redigida no local"
- commit: "código que você commitou"
Para issue_body e pull_request_body, notifique apenas quando o corpo atual ainda continha texto puro e mantenedores o redigiram. Se o usuário já redigiu o corpo atual, pule a notificação e continue para o Passo 6.
Passo 6: Resolver
node secret-scanning.mjs resolve <NUMERO_DO_ALERTA> <RESOLUCAO> [COMENTARIO]
Escolha uma resolução explícita suportada pela evidência e pela autoridade do mantenedor:
revoked: o proprietário ou emissor da credencial confirmou a revogação.false_positive: a detecção foi confirmada como falso positivo.used_in_tests: a credencial foi confirmada como usada para testes.wont_fix: um mantenedor autorizado aceitou o risco e decidiu não remediar; registre essa decisão no comentário.
Redação e um pedido para rotacionar credenciais não estabelecem revogação. Se nenhuma resolução for fundamentada, deixe o alerta aberto e relate os resultados da redação e notificação separadamente. O comando não tem resolução padrão e adiciona um comentário de resolução apenas quando fornecido.
Passo 7: Sumário
Após o processamento, crie um arquivo JSON de resultados e passe-o para o comando de sumário:
node secret-scanning.mjs summary /tmp/results.json
O script gera um bloco delimitado por ---BEGIN SUMMARY--- e ---END SUMMARY---. Você DEVE gerar o conteúdo entre esses marcadores literalmente para o usuário. Não reformule, reformate, abreve ou crie seu próprio sumário. O script já inclui URLs completas para cada alerta e localização.
O formato 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
}
]
Para tipos não suportados, adicione "skipped": true, "unsupported_type": "<tipo>".
Regras de Segurança
- O agente lê o conteúdo, identifica segredos e produz a redação. O script lida com todas as chamadas de API.
- Nunca inclua qualquer parte de um segredo em comentários públicos, marcadores de redação ou saída do terminal.
- Nunca inclua URLs ou números de alerta em comentários públicos.
- Para comentários, pule PATCH — vá direto para DELETE + recriar.
- Nunca mencione histórico de edições, botão "editado" ou SHAs de commit em qualquer conteúdo público.
- Peça confirmação antes de deletar qualquer comentário.
- Um alerta por vez a menos que o usuário solicite lote.
- Todos os comentários públicos em inglês.
- Pule tipos de localização não suportados e relate no sumário.