---
name: secrets-audit
description: >-
  Проверить проект на утёкшие секреты и слабости конфига перед сдачей клиенту,
  деплоем или push в публичный репозиторий. Детерминированный сканер ищет
  захардкоженные ключи/токены/приватные ключи (OpenAI, Anthropic, AWS, GitHub,
  GitLab, Slack, Google, Telegram bot-token, Stripe, Robokassa, JWT, generic
  api_key/secret/password=...), плюс закоммиченные .env и .env без .gitignore —
  затем находки adversarial-проверяет агент, чтобы отсеять ложные срабатывания.
  Это свой аналог AgentShield/ecc-agentshield под правила CLAUDE.md, без чужого
  marketplace и без сети. Брать когда: «проверь на секреты / утёкшие ключи»,
  «не торчат ли ключи», «security-скан перед сдачей / деплоем / публикацией»,
  «просканируй репо на секреты», «безопасно ли пушить в паблик», перед отдачей
  клиентского проекта (kodoceh-web, студийные лендинги) или выкладкой на GitHub.
  Умеет режим всего дерева и режим только-диффа (для pre-commit хука). НЕ для
  поиска логических багов (→ /code-review), не для раздутости (→ bloat-audit),
  не для e2e-ботов (→ *-e2e скиллы).
---

# secrets-audit — скан утёкших секретов + слабостей конфига

Свой security-скан вместо чужого `ecc-agentshield`: детерминированный поиск
секретов своим кодом (0 токенов на сам скан, без сети), поверх — adversarial-
верификация агентом (CLAUDE.md §7 — не «должно быть чисто», а проверено).

## Что ищет сканер (`tools/scan.py`)
- **Захардкоженные ключи/токены** по префиксам: OpenAI `sk-`, Anthropic `sk-ant-`,
  AWS `AKIA…`, GitHub `ghp_/gho_/…`, GitLab `glpat-`, Slack `xox…` + webhook,
  Google `AIza…`, Telegram bot `123:AA…`, Stripe `sk_live_…`, Robokassa MRH_pass,
  JWT `eyJ…`, приватные ключи `-----BEGIN … PRIVATE KEY-----`.
- **Generic-присвоения** `api_key/secret/token/password = "…"` с энтропийным
  фильтром (плейсхолдеры `your-…`, `${VAR}`, `os.environ[…]`, `<...>` отсеиваются).
- **Слабости конфига**: `.env` закоммичен в git (HIGH), `.env` не покрыт
  `.gitignore` (MEDIUM).

Severity: **HIGH** — почти наверняка настоящий секрет; **MEDIUM** — вероятный,
проверить глазами; **LOW** — только по энтропии.

## Процесс

### Шаг 1 — скан (детерминированно, дёшево)
```
python3 ~/.claude/skills/secrets-audit/tools/scan.py [PROJECT_DIR]           # весь трекнутый код
python3 ~/.claude/skills/secrets-audit/tools/scan.py [PROJECT_DIR] --diff    # только незакоммиченный дифф
python3 ~/.claude/skills/secrets-audit/tools/scan.py [PROJECT_DIR] --staged  # только staged (для хука)
python3 ~/.claude/skills/secrets-audit/tools/scan.py [PROJECT_DIR] --json    # машинный вывод для агента
```
В git-репо сканирует только трекнутые файлы (то, что реально уедет в паблик).
Вне git — всё дерево, кроме `node_modules/.venv/dist/…`. Exit: `1`=есть HIGH,
`2`=только MEDIUM/LOW, `0`=чисто.

### Шаг 2 — adversarial-верификация (агентом, обязательно)
Regex-скан **шумит** — тестовые фикстуры, примеры из доков, публичные ключи,
захардкоженные не-секреты. По каждой HIGH/MEDIUM находке (`--json`) прогони
`general-purpose`/`Explore` агента с промптом:
«Открой file:line. Это НАСТОЯЩИЙ живой секрет или ложное срабатывание (тестовая
фикстура, пример в доке, публичный/отозванный ключ, плейсхолдер, значение из
env)? Верни verdict=real|false + одну строку обоснования». Много находок —
верифицируй пачкой параллельно. Оставь только `real`.

### Шаг 3 — отчёт и ремедиация (СТОП, спроси перед правками)
Покажи пользователю подтверждённые находки. Ремедиацию (вынести в `.env`,
`git rm --cached`, ротация ключа, добавить в `.gitignore`) предлагай, но
**сам ключи никуда не вводи и не ротируй** — это прерогатива пользователя
(prohibited: работа с чужими креденшелами). Если секрет уже в истории git —
предупреди, что `.gitignore` его не удалит, нужен `git filter-repo`/ротация.

## Опционально — pre-commit хук
Чтобы скан шёл сам перед каждым коммитом (CLAUDE.md §6 — автоматизируй
повторяемое), предложи пользователю `.git/hooks/pre-commit`:
```sh
#!/bin/sh
python3 ~/.claude/skills/secrets-audit/tools/scan.py "$(git rev-parse --show-toplevel)" --staged || {
  echo "secrets-audit: найдены кандидаты в секреты — коммит остановлен. Проверь вывод выше."; exit 1; }
```

## Границы (честно)
- Ловит **известные форматы** и generic-присвоения. Секрет без узнаваемого
  префикса в «голой» переменной без ключевого слова — regex не увидит; на такое
  и нужен агент из шага 2, читающий контекст.
- Не сканирует **историю git** — только текущее состояние/дифф.
- Не проверяет права доступа/облачные IAM (это не в скоупе локального скана).
