OpenClaw Secret Scanning 유지보수자
유지보수자 전용. 이 스킬은 다른 사용자의 댓글을 편집/삭제하고 비밀 검사 알림을 해결하려면 저장소 관리자/유지보수자 권한이 필요합니다.
이 스킬은 https://github.com/openclaw/openclaw/security/secret-scanning의 알림을 처리할 때 사용합니다.
언어 규칙: 모든 알림 댓글과 대체 댓글은 반드시 영어로 작성해야 합니다.
스크립트
모든 기계적 작업(API 호출, 임시 파일 관리, 보안 강화)은 다음에서 처리합니다:
$REPO_ROOT/.agents/skills/openclaw-secret-scanning-maintainer/scripts/secret-scanning.mjs
스크립트는 다음을 강제합니다:
- 모든 알림 조회 시
hide_secret=true(표준 출력에 평문 비밀 없음) - 모든 임시 파일에 대해 무작위 UUID를 사용하는
mktemp - 모든 본문 업로드는
-F body=@file사용 (인라인 셸 따옴표 없음) - 위치 유형별로 분기된 알림 템플릿
- 표준 출력에
.secret또는.body절대 출력 금지
전체 흐름
단일 또는 여러 알림을 지원합니다. 여러 알림의 경우 오름차순으로 처리합니다.
각 알림에 대해:
- 식별 —
fetch-alert+fetch-content로 메타데이터와 본문 가져오기 - 결정 — 에이전트가 본문 파일을 읽고 평문 비밀이 남아 있는지 식별하며, 필요한 경우에만 교정 버전 생성
- 교정 — 이슈/PR 본문에는
redact-body-if-needed사용; 댓글은 건너뛰기 (직접 삭제) - 정리 — 댓글은
delete-comment+recreate-comment사용; 본문 기록은 정리 불가 - 알림 — 위치 유형별 올바른 템플릿으로
notify실행, 단 현재 이슈/PR 본문이 이미 교정된 경우 제외 - 해결 —
resolve로 알림 종료 - 요약 —
summary로 형식화된 결과 출력
1단계: 식별
# 열려 있는 모든 알림 나열
node secret-scanning.mjs list-open
# 특정 알림 메타데이터 + 위치 가져오기
node secret-scanning.mjs fetch-alert <NUMBER>
# 각 위치의 콘텐츠 가져오기 (본문을 임시 파일에 저장)
node secret-scanning.mjs fetch-content '<location-json>'
fetch-content 출력에는 다음이 포함됩니다:
body_file: 전체 본문 내용이 있는 임시 파일 경로author: 게시자issue_number/pr_number: 위치edit_history_count: 기존 편집 횟수type: 라우팅을 위한 위치 유형discussion_comment의 경우 원래 댓글이 답글이면comment_node_id,discussion_node_id,reply_to_node_id도 포함
위치 유형 라우팅
| 유형 | 흐름 |
|---|---|
issue_comment | 댓글: 삭제+재생성 |
pull_request_comment | 댓글: 삭제+재생성 |
pull_request_review_comment | 댓글: 삭제+재생성 |
discussion_comment | 토론 댓글: 삭제+재생성 (GraphQL) |
issue_body | 본문: 제자리 교정 |
pull_request_body | 본문: 제자리 교정 |
commit | 알림만 |
| 기타 | 건너뛰고 보고 |
2단계: 결정 (에이전트)
에이전트는 fetch-content 출력에서 본문 파일을 읽고:
- 콘텐츠의 모든 비밀 식별 (알림이 표시한 것보다 더 많을 수 있음)
- 현재 본문에 평문 자격 증명이 남아 있는지 결정
- 각 남아 있는 비밀을
[REDACTED <secret_type>]로 대체 — 부분 값, 접두사/접미사 없음 - 교정된 콘텐츠를 새 임시 파일에 저장
이 단계만 의미론적 이해가 필요합니다. 나머지는 모두 기계적입니다.
issue_body 및 pull_request_body의 경우: 현재 본문이 작성자에 의해 이미 교정되었고 평문 자격 증명이 남아 있지 않으면 공개 알림 댓글을 게시하지 마십시오. 이는 과거 민감한 콘텐츠에 대한 새로운 공개 포인터를 생성하는 것을 방지합니다. 교정을 별도로 기록하고 6단계를 사용하여 증거가 알림 해결을 뒷받침하는지 결정합니다.
3단계: 교정
댓글(issue_comment / PR 댓글)의 경우
교정하지 마십시오. 4단계(삭제 + 재생성)로 직접 건너뜁니다. 삭제 전 PATCH는 불필요한 편집 기록 개정을 만듭니다.
issue_body / pull_request_body의 경우
node secret-scanning.mjs redact-body-if-needed <issue|pr> <NUMBER> <current-body-file> <redacted-body-file> <result-file>
fetch-content의 body_file을 <current-body-file>로 사용합니다. 명령은 <result-file>에 notify_required를 쓰고 교정된 파일이 현재 본문과 다른 경우에만 본문을 PATCH합니다.
4단계: 편집 기록 제거
댓글 — 삭제 및 재생성
이슈/PR 댓글의 경우:
# 원본 삭제 (모든 편집 기록 제거)
node secret-scanning.mjs delete-comment <COMMENT_ID>
# 교정된 콘텐츠로 재생성
node secret-scanning.mjs recreate-comment <ISSUE_NUMBER> <body-file>
토론 댓글의 경우 (GraphQL 사용):
# 원본 삭제
node secret-scanning.mjs delete-discussion-comment <COMMENT_NODE_ID>
# 교정된 콘텐츠로 재생성
node secret-scanning.mjs recreate-discussion-comment <DISCUSSION_NODE_ID> <body-file> [REPLY_TO_NODE_ID]
discussion_comment에 대한 fetch-content 출력에는 이 명령을 위한 comment_node_id와 discussion_node_id가 포함됩니다. 원래 토론 댓글이 답글이면 reply_to_node_id도 포함합니다. 이 선택적 세 번째 인수를 전달하여 교정된 대체물이 원래 스레드에 유지되도록 합니다.
재생성된 댓글은 다음 형식을 따라야 합니다:
> **참고:** @<AUTHOR>의 원래 댓글은 비밀 유출로 인해 제거되었습니다. 아래는 원래 콘텐츠의 교정된 버전입니다.
---
<교정된 원래 콘텐츠>
issue_body / pull_request_body — 편집 기록 제거 불가
편집은 편집 전 평문이 포함된 편집 기록 개정을 만듭니다. API를 통해 이를 지울 수 없습니다.
작성자에게 공개적으로 이슈/PR을 삭제/재생성하거나 닫기/다시 열라고 조언하지 마십시오. 이는 민감한 기록 콘텐츠에 주의를 끌 수 있습니다. 제거 지침은 유지보수자 전용으로 유지합니다.
유지보수자 터미널에만 출력 (공개 댓글에는 절대 출력 금지):
⚠️ 이슈/PR 본문 편집 기록에 여전히 평문 비밀이 포함되어 있습니다.
GitHub 지원팀에 문의하여 제거하세요: https://support.github.com/contact
이슈/PR #{NUMBER} userContentEdits의 제거를 요청하세요.
중요: 공개 댓글이나 해결 댓글에서 편집 기록이나 "편집" 버튼을 언급하지 마십시오.
커밋
정리할 수 없습니다. 작성자에게 브랜치를 삭제하거나 강제 푸시하도록 알립니다(병합되지 않은 PR의 경우).
5단계: 알림
node secret-scanning.mjs notify <TARGET> <AUTHOR> <LOCATION_TYPE> <SECRET_TYPES> [REPLY_TO_NODE_ID|BODY_REDACTION_RESULT_FILE]
- 비토론 유형의 경우
<TARGET>은 이슈/PR 번호입니다. discussion_comment의 경우<TARGET>은fetch-content가 반환한discussion_node_id입니다.- 답글 스타일
discussion_comment위치의 경우fetch-content의 선택적reply_to_node_id를 전달하여 알림이 동일한 스레드에 유지되도록 합니다. issue_body및pull_request_body의 경우redact-body-if-needed의<result-file>을 전달합니다. 스크립트는notify_required가false이면 알림을 건너뛰고 이 파일 없이 본문 알림을 거부합니다.
비밀 유형은 쉼표로 구분합니다: "Discord Bot Token,Feishu App Secret"
스크립트가 올바른 템플릿을 선택합니다:
- 댓글 유형: "귀하의 댓글 … 제거되고 대체되었습니다"
- 본문 유형: "귀하의 이슈/PR 설명 … 제자리에서 교정되었습니다"
- 커밋: "귀하가 커밋한 코드"
issue_body 및 pull_request_body의 경우 현재 본문에 여전히 평문이 포함되어 있고 유지보수자가 교정한 경우에만 알립니다. 사용자가 이미 현재 본문을 교정했다면 알림을 건너뛰고 6단계로 계속합니다.
6단계: 해결
node secret-scanning.mjs resolve <ALERT_NUMBER> <RESOLUTION> [COMMENT]
증거와 유지보수자의 권한이 뒷받침하는 명시적 해결 방법을 선택합니다:
revoked: 자격 증명 소유자 또는 발급자가 취소를 확인했습니다.false_positive: 탐지가 오탐지로 확인되었습니다.used_in_tests: 자격 증명이 테스트에 사용된 것으로 확인되었습니다.wont_fix: 권한이 있는 유지보수자가 위험을 수락하고 수정하지 않기로 결정했습니다. 그 결정을 댓글에 기록합니다.
교정 및 자격 증명 순환 요청은 취소를 입증하지 않습니다. 입증된 해결 방법이 없으면 알림을 열린 상태로 두고 교정 및 알림 결과를 별도로 보고합니다. 명령에는 기본 해결 방법이 없으며 해결 방법이 제공된 경우에만 해결 댓글을 추가합니다.
7단계: 요약
처리가 끝나면 JSON 결과 파일을 만들어 요약 명령에 전달합니다:
node secret-scanning.mjs summary /tmp/results.json
스크립트는 ---BEGIN SUMMARY---와 ---END SUMMARY---로 구분된 블록을 출력합니다. 이 마커 사이의 내용을 사용자에게 그대로 출력해야 합니다. 다시 말하거나, 형식을 바꾸거나, 축약하거나, 자신만의 요약을 만들지 마십시오. 스크립트에는 이미 모든 알림과 위치에 대한 전체 URL이 포함되어 있습니다.
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>"을 추가합니다.
안전 규칙
- 에이전트가 콘텐츠를 읽고, 비밀을 식별하며, 교정을 생성합니다. 스크립트가 모든 API 호출을 처리합니다.
- 공개 댓글, 교정 표시 또는 터미널 출력에 비밀의 어떤 부분도 포함하지 마십시오.
- 공개 댓글에 알림 URL이나 번호를 포함하지 마십시오.
- 댓글의 경우 PATCH를 건너뛰고 — 직접 DELETE + 재생성으로 이동합니다.
- 공개 콘텐츠에서 편집 기록, "편집" 버튼 또는 커밋 SHA를 언급하지 마십시오.
- 댓글을 삭제하기 전에 확인을 요청하십시오.
- 사용자가 일괄 처리를 요청하지 않는 한 한 번에 하나의 알림을 처리합니다.
- 모든 공개 댓글은 영어로 작성합니다.
- 지원되지 않는 위치 유형은 건너뛰고 요약에 보고합니다.