diff --git a/README.md b/README.md new file mode 100644 index 0000000..8ad4eae --- /dev/null +++ b/README.md @@ -0,0 +1,154 @@ +# Adversarial Review + +Claude Code skill for adversarial AI code and plan review. + +One AI writes the code. Another tears it apart. Iterate until approved. + +## What is this + +Most AI code review tools validate your changes — "looks good, maybe add tests." +Adversarial review does the opposite: the reviewer **defaults to skepticism** +and tries to break confidence in the change. It looks for what will fail +in production, not what might be nice to improve. + +This is a [Claude Code skill](https://docs.anthropic.com/en/docs/claude-code) +— a single `SKILL.md` file that teaches Claude how to run adversarial reviews +through an external AI model (currently OpenAI Codex). + +## Key features + +**Two stages** — works on both planning and implementation: +- **Plan review** — review the plan BEFORE writing code. Catch architecture + mistakes, missing steps, and risks early +- **Code review** — review the implementation. Bugs, security, data loss +- **Code-vs-plan** — verify the implementation matches the plan + +**Lightweight** — one file, no server, no broker, no dependencies beyond +the reviewer CLI. Compare with [codex-plugin-cc](https://github.com/openai/codex-plugin-cc): +~15 JS modules, App Server, JSON-RPC broker, lifecycle hooks. +This skill is a text instruction that any AI agent can interpret. + +**Iterative** — Claude doesn't just show the review and stop. +It actively fixes issues based on reviewer feedback and resubmits +for re-review. Up to 5 rounds until approved. + +**Universal foundation** — the skill relies on basic agent capabilities: +run a command, read a file, edit a file. The reviewer is a swappable +component: today Codex, tomorrow Gemini CLI, next week a local model. +Switching backends = changing one launch command; prompts and workflow stay the same. + +## How it works + +``` +┌─────────┐ ┌──────────┐ ┌─────────┐ +│ Claude │────>│ Reviewer │────>│ Claude │ +│ (code) │ │ (Codex) │ │ (fix) │ +└─────────┘ └──────────┘ └─────────┘ + ^ │ + │ ┌──────────┐ │ + └─────────│ Reviewer │<───────────┘ + │(re-review)│ + └──────────┘ + │ + VERDICT: APPROVED +``` + +### Three modes + +| Mode | What it reviews | When to use | +|------|----------------|-------------| +| `plan` | Implementation plan | Before writing code | +| `code` | Git diff (unstaged, staged, or branch) | After writing code | +| `code-vs-plan` | Code changes against the plan | Verify implementation matches plan | + +Mode is auto-detected from context, or you can force it with an argument. + +## Installation + +### Requirements + +- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) +- [OpenAI Codex CLI](https://github.com/openai/codex): `npm install -g @openai/codex` +- OpenAI API key (`OPENAI_API_KEY` environment variable) + +### Setup + +```bash +# Clone the repository +git clone https://github.com//adversarial-review.git + +# Symlink into Claude Code skills directory +ln -s "$(pwd)/adversarial-review" ~/.agents/skills/adversarial-review +``` + +After symlinking, the skill is available as `/adversarial-review` in Claude Code. + +## Usage + +``` +# Auto-detect what to review +/adversarial-review + +# Review a plan +/adversarial-review plan + +# Review code changes +/adversarial-review code + +# Review a specific file +/adversarial-review path/to/plan.md + +# Use higher reasoning effort +/adversarial-review xhigh + +# Use a different model +/adversarial-review model:gpt-5.3-codex +``` + +## Prompt architecture + +The skill uses XML-structured prompts inspired by adversarial review methodology: + +- **``** — adversarial reviewer, defaults to skepticism +- **``** — break confidence, not validate +- **``** — concrete checklist: auth, data integrity, + race conditions, rollback safety, schema drift, error handling, observability +- **``** — every finding must answer 4 questions: + what can go wrong, why this code is vulnerable, impact, recommendation +- **``** — no style, naming, or speculative comments +- **``** — one strong finding > five weak ones + +## Example output + +See [examples/review-output.md](examples/review-output.md) for a sample +adversarial review output. + +## Roadmap + +- [ ] Gemini as alternative reviewer backend +- [ ] Local model support (Ollama, llama.cpp) +- [ ] CI integration (GitHub Actions) +- [ ] Multi-reviewer mode (parallel review by multiple models) + +## Inspiration + +The adversarial prompt structure was developed after studying +[openai/codex-plugin-cc](https://github.com/openai/codex-plugin-cc) (Apache-2.0) +— the official OpenAI plugin for code review with Codex in Claude Code. + +What we borrowed as ideas: +- XML-structured prompts (``, ``, ``, etc.) +- Adversarial stance: "break confidence, not validate" +- Attack surface checklist approach +- Finding bar: 4 questions each finding must answer +- Calibration rules: prefer strong findings over weak ones + +What we did differently: +- **Iterative loop** — Claude actively fixes issues and resubmits (vs "stop and ask user") +- **Plan review** — reviews plans before code, not just code +- **Single file** — one SKILL.md vs 15+ JS modules with App Server +- **Verbatim output** — reviewer findings shown as-is, not rephrased + +## License + +Apache-2.0 — see [LICENSE](LICENSE). diff --git a/SKILL.md b/SKILL.md index 3b82ca6..96de1af 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,23 +1,23 @@ --- -name: codex-review -description: Ревью плана или кода через OpenAI Codex. Автодетект режима, итеративные правки до одобрения. +name: adversarial-review +description: Adversarial AI code/plan review. Codex ревьюит, Claude правит, итеративный цикл до одобрения. Автодетект режима plan/code/code-vs-plan. user_invocable: true --- -# Итеративное ревью через Codex +# Adversarial Code Review -Отправляет текущую работу в OpenAI Codex на adversarial-ревью. Автоматически определяет, что ревьюить: **план** или **код**. Claude правит по замечаниям Codex и переотправляет до одобрения. Максимум 5 раундов. +Отправляет текущую работу на adversarial-ревью через внешнюю AI-модель (по умолчанию — OpenAI Codex). Автоматически определяет, что ревьюить: **план** или **код**. Claude правит по замечаниям ревьюера и переотправляет до одобрения. Максимум 5 раундов. --- ## Когда вызывать -- `/codex-review` — автодетект что ревьюить -- `/codex-review plan` — принудительно ревью плана -- `/codex-review code` — принудительно ревью кода -- `/codex-review <путь-к-файлу>` — ревью конкретного файла (аргумент содержит `/` или `.`) -- Переопределение reasoning: `/codex-review xhigh` или `/codex-review low` (одно из: `none`, `low`, `medium`, `high`, `xhigh`) -- Переопределение модели: `/codex-review model:gpt-5.3-codex` (аргумент с префиксом `model:`) +- `/adversarial-review` — автодетект что ревьюить +- `/adversarial-review plan` — принудительно ревью плана +- `/adversarial-review code` — принудительно ревью кода +- `/adversarial-review <путь-к-файлу>` — ревью конкретного файла (аргумент содержит `/` или `.`) +- Переопределение reasoning: `/adversarial-review xhigh` или `/adversarial-review low` (одно из: `none`, `low`, `medium`, `high`, `xhigh`) +- Переопределение модели: `/adversarial-review model:gpt-5.3-codex` (аргумент с префиксом `model:`) ## Инструкции @@ -93,11 +93,11 @@ git rev-parse --verify main 2>/dev/null && echo main || echo master Branch берётся ТОЛЬКО когда нет локальных изменений — иначе контекст раздувается. Для branch в промпте указывай команду `git diff ${BASE_BRANCH}...HEAD` (полный diff). -Codex имеет доступ к репо и сам прочитает полный diff и файлы. +Ревьюер имеет доступ к репо и сам прочитает полный diff и файлы. В промпт (шаг 4) передай список файлов и какие git diff команды запускать. **Много файлов (> 50):** если объединённый список превышает 50 путей, -передай в промпт только git-команды без списка файлов — Codex разберётся сам. +передай в промпт только git-команды без списка файлов — ревьюер разберётся сам. Если все источники пусты — нет изменений для ревью, сообщи пользователю. @@ -105,64 +105,182 @@ Codex имеет доступ к репо и сам прочитает полн ### Шаг 4: Сформировать промпт и запустить первый раунд -Сформируй промпт в зависимости от режима: +Сформируй промпт в зависимости от режима. Все промпты используют adversarial stance. **Промпт для ревью плана:** + ``` -Review the implementation plan in . Focus on: -1. Correctness — will this plan achieve the stated goals? -2. Risks — what could go wrong? Edge cases? Data loss? -3. Missing steps — is anything forgotten? -4. Alternatives — is there a simpler or better approach? -5. Security — any security concerns? + +You are a senior adversarial reviewer of implementation plans. +Your job is to break confidence in the plan, not to validate it. + + + +Default to skepticism. Assume the plan has gaps until the evidence says otherwise. +Do not give credit for good intent or likely follow-up work. +If something only works on the happy path, treat that as a real weakness. + + + +Review the implementation plan in . + + + +Check each area. Skip if not applicable: +- Feasibility — will this approach actually work given the codebase and constraints? +- Missing steps — what is forgotten or assumed but not stated? +- Risk areas — what could go wrong during implementation? Data loss? Downtime? +- Sequencing — are steps in the right order? Are there hidden dependencies? +- Alternatives — is there a simpler or more robust approach? +- Rollback — can this be safely reverted if it fails halfway? +- Security — auth, data exposure, injection, unsafe operations + + + +Each finding MUST answer: +1. What can go wrong? (concrete scenario, not hypothetical) +2. Why is this plan vulnerable? (cite specific section) +3. Impact — what breaks and how badly? +4. Recommendation — specific change to the plan + + + +DO NOT comment on: formatting, wording style, speculative issues without concrete trigger scenario. + + + +Prefer one strong finding over several weak ones. +If the plan is solid, say so clearly — false positives erode trust. + + + +## Summary +One paragraph: what this plan does and your overall assessment. + +## Findings +For each finding: +### [severity: critical|high|medium] Finding title +- **Section:** which part of the plan +- **What can go wrong:** ... +- **Why vulnerable:** ... +- **Impact:** ... +- **Recommendation:** ... + +If no findings: "No actionable findings." + +## Verdict +VERDICT: APPROVED — no findings, or all findings are low severity +VERDICT: REVISE — one or more high/critical findings + ``` **Промпт для ревью кода (<= 50 файлов):** + ``` + +You are a senior adversarial code reviewer. +Your job is to break confidence in the change, not to validate it. + + + +Default to skepticism. Assume the change can fail in subtle, high-cost, +or user-visible ways until the evidence says otherwise. +Do not give credit for good intent, partial fixes, or likely follow-up work. +If something only works on the happy path, treat that as a real weakness. + + + Review the code changes in this repo. Changed files: <список файлов из --name-only> Changes include: . -Run to see the full diffs. Focus on: -1. Bugs — logic errors, off-by-one, null handling, race conditions -2. Edge cases — what inputs or states could break this? -3. Style — does the code follow existing project conventions? -4. Security — injection, credential exposure, unsafe operations -5. Tests — is the change adequately tested? +Run to see the full diffs. + + + +Check each area. Skip if not applicable to this change: +- Auth & permissions: bypasses, privilege escalation, missing checks +- Data integrity: loss, corruption, partial writes, constraint violations +- Race conditions: TOCTOU, concurrent access, deadlocks +- Rollback safety: can this change be safely reverted? +- Schema drift: migrations, backward compatibility, data format changes +- Error handling: swallowed errors, missing retries, cascading failures +- Observability: will operators know when this breaks? + + + +Each finding MUST answer: +1. What can go wrong? (concrete scenario, not hypothetical) +2. Why is this code vulnerable? (cite specific file and lines) +3. Impact — what breaks and how badly? (data loss > downtime > degraded UX) +4. Recommendation — specific fix with code reference + + + +DO NOT comment on: code style, formatting, naming conventions, +speculative issues without concrete trigger scenario, +"nice to have" improvements unrelated to correctness or safety. + + + +Prefer one strong finding over several weak ones. +Severity: critical (data loss/security) > high (bug in prod) > medium (edge case). +If the change is solid, say so clearly — false positives erode trust. + + + +## Summary +One paragraph: what this change does and your overall assessment. + +## Findings +For each finding: +### [severity: critical|high|medium] Finding title +- **File:** path/to/file.ext lines N-M +- **What can go wrong:** ... +- **Why vulnerable:** ... +- **Impact:** ... +- **Recommendation:** ... + +If no findings: "No actionable findings." + +## Verdict +VERDICT: APPROVED — no findings, or all findings are low severity +VERDICT: REVISE — one or more high/critical findings + ``` **Промпт для ревью кода (> 50 файлов):** + +Тот же промпт, что выше, но секция `` без списка файлов: ``` + Review the code changes in this repo. Changes include: . -Run to see changed files and full diffs. Focus on: -1. Bugs — ... -(те же 5 пунктов) +Run to see changed files and full diffs. + ``` **Промпт для ревью кода против плана:** + +Тот же промпт для ревью кода, но секция `` дополняется: ``` + Review the code changes in this repo against the implementation plan in . Changed files: <список файлов или пусто если > 50> Changes include: <тип>. -Run to see the full diffs. Focus on: -1. Completeness — does the implementation cover all plan steps? -2. Deviations — where does the code differ from the plan? Are deviations justified? -3. Bugs — logic errors, edge cases, null handling -4. Security — injection, credential exposure, unsafe operations -5. Missing — what from the plan is not yet implemented? +Run to see the full diffs. + ``` -**Все промпты заканчиваются:** +И в `` добавляются пункты: ``` -Be specific and actionable. Reference file paths and line numbers where possible. - -If the work is solid and ready, end your review with exactly: VERDICT: APPROVED -If changes are needed, end with exactly: VERDICT: REVISE +- Completeness: does the implementation cover all plan steps? +- Deviations: where does the code differ from the plan? Are deviations justified? +- Missing: what from the plan is not yet implemented? ``` **Запуск Codex — шаблон команды:** @@ -170,7 +288,7 @@ If changes are needed, end with exactly: VERDICT: REVISE Флаги: - `-m gpt-5.4` — модель (переопределяется аргументом `model:...`) - `-c model_reasoning_effort=high` — глубина рассуждения (переопределяется аргументом `xhigh`, `low` и т.д.) -- `-s read-only` — Codex только читает, не пишет +- `-s read-only` — ревьюер только читает, не пишет - `-o /tmp/codex-review-${REVIEW_ID}.md` — файл для записи ответа ```bash @@ -188,42 +306,22 @@ timeout 600 codex exec \ - Команда **синхронная**: когда она вернулась, файл `-o` уже готов. **НЕ** используй poll-loop (`while/sleep`). - Если exit code = 124 (таймаут) — сообщи пользователю и предложи повторить. -**Пример для режима code** (unstaged изменения в двух файлах): - -```bash -timeout 600 codex exec \ - -m gpt-5.4 \ - -c model_reasoning_effort=high \ - -s read-only \ - -o /tmp/codex-review-${REVIEW_ID}.md \ - "Review the code changes in this repo. Changed files: - -agents/.agents/skills/codex-review/SKILL.md -TODO.md - -Changes include: unstaged changes. -Run git diff to see the full diffs. Focus on: -1. Bugs — logic errors, off-by-one, null handling, race conditions -... -If changes are needed, end with exactly: VERDICT: REVISE" -``` - **После запуска:** найди в выводе строку `session id: ` и сохрани значение как `CODEX_SESSION_ID` — оно нужно для `resume` в последующих раундах. **Примечания:** - Модель по умолчанию: `gpt-5.4` с `model_reasoning_effort=high`. Пользователь может переопределить через аргументы. -- Всегда `-s read-only` — Codex не должен писать файлы. +- Всегда `-s read-only` — ревьюер не должен писать файлы. - `-o` для захвата вывода в файл. **НЕ** запускай в background — команда сама вернёт управление. ### Шаг 5: Прочитать ревью и проверить вердикт 1. Прочитать `/tmp/codex-review-${REVIEW_ID}.md` -2. Показать пользователю: +2. Показать пользователю **дословно** (verbatim) — не перефразировать findings ревьюера: ``` -## Codex Review — Раунд N (режим: , модель: gpt-5.4) +## Adversarial Review — Раунд N (режим: , модель: gpt-5.4) -[Отзыв Codex] +[Отзыв ревьюера — дословно] ``` 3. Проверить вердикт: @@ -234,7 +332,7 @@ If changes are needed, end with exactly: VERDICT: REVISE" ### Шаг 6: Внести правки -По замечаниям Codex: +По замечаниям ревьюера: **Для ревью плана:** исправить план — адресовать каждое замечание. Обновить файл плана (или temp-файл). Показать пользователю: @@ -254,7 +352,7 @@ If changes are needed, end with exactly: VERDICT: REVISE" ### Шаг 7: Переотправить в Codex (Раунды 2-5) -**Resume — основной путь.** Экономит токены и сохраняет контекст сессии Codex. Свежий `codex exec` без resume — **аварийный fallback**, расходует значительно больше токенов. Использовать только при ошибке resume. +**Resume — основной путь.** Экономит токены и сохраняет контекст сессии. Свежий `codex exec` без resume — **аварийный fallback**, расходует значительно больше токенов. Использовать только при ошибке resume. 1. Запусти resume с подавлением stderr (`2>/dev/null`): @@ -265,7 +363,11 @@ timeout 600 codex exec resume ${CODEX_SESSION_ID} \ Here's what I changed: [Список правок] -Please re-review. End with VERDICT: APPROVED or VERDICT: REVISE" 2>/dev/null +Re-review with the same adversarial stance. Focus on: +1. Whether my fixes actually resolve the reported issues +2. Any NEW issues introduced by the fixes + +End with VERDICT: APPROVED or VERDICT: REVISE" 2>/dev/null ``` Используй `timeout: 620000` в параметрах Bash tool. @@ -274,7 +376,7 @@ Please re-review. End with VERDICT: APPROVED or VERDICT: REVISE" 2>/dev/null 2. Проверь результат по exit code: - **exit 0** — успех. stdout содержит чистое ревью. Показать пользователю напрямую (Write в файл и Read **не нужны**). Проверить VERDICT: последняя непустая строка stdout = `VERDICT: APPROVED` или `VERDICT: REVISE`. Если вердикт отсутствует → вывод мог быть обрезан, перейти к Fallback. Далее применить обработку вердикта из Шага 5 (APPROVED → Шаг 8, REVISE → Шаг 6). - - **exit 124** — таймаут. Сообщи пользователю: "Codex не ответил за 10 минут" и предложи повторить. + - **exit 124** — таймаут. Сообщи пользователю: "Ревьюер не ответил за 10 минут" и предложи повторить. - **другой exit code** — сообщи пользователю: "Resume не удался (exit code N)". Перейди к Fallback. Диагностика без stderr недоступна — не пытайся парсить stdout как ошибку. **Fallback** — если `resume` не сработал (сессия истекла, session ID не захвачен, ошибка): @@ -288,19 +390,19 @@ Please re-review. End with VERDICT: APPROVED or VERDICT: REVISE" 2>/dev/null **Одобрено:** ``` -## Codex Review — Итог (режим: <режим>, модель: gpt-5.4) +## Adversarial Review — Итог (режим: <режим>, модель: gpt-5.4) **Статус:** ✅ Одобрено после N раунд(ов) [Итоговый отзыв] --- -**Проверено и одобрено Codex. Ожидает вашего решения.** +**Проверено и одобрено ревьюером. Ожидает вашего решения.** ``` **Достигнут максимум раундов:** ``` -## Codex Review — Итог (режим: <режим>, модель: gpt-5.4) +## Adversarial Review — Итог (режим: <режим>, модель: gpt-5.4) **Статус:** ⚠️ Достигнут максимум (5 раундов) — не полностью одобрено @@ -308,7 +410,7 @@ Please re-review. End with VERDICT: APPROVED or VERDICT: REVISE" 2>/dev/null [Нерешённые вопросы] --- -**У Codex остались замечания. Просмотрите их и решите, как действовать дальше.** +**У ревьюера остались замечания. Просмотрите их и решите, как действовать дальше.** ``` ### Шаг 9: Очистка @@ -327,13 +429,14 @@ rm -f /tmp/claude-plan-${REVIEW_ID}.md /tmp/codex-review-${REVIEW_ID}.md ## Правила -- Claude **активно правит** по замечаниям Codex — это НЕ просто передача сообщений +- Claude **активно правит** по замечаниям ревьюера — это НЕ просто передача сообщений +- Findings ревьюера показываются **дословно** (verbatim) — не перефразировать, не сокращать - Автодетект режима ревью по контексту; аргументы пользователя имеют приоритет - При явном аргументе `plan` или в Claude Code Plan Mode: пропускать git-проверки и определение base branch - Resume — основной путь для повторных раундов. Свежий exec — аварийный fallback (дорогой по токенам) - Cleanup — best-effort: в Plan Mode пропускать, при отказе продолжать без ошибки - Предпочитать существующие файлы, не создавать лишние копии -- Всегда read-only sandbox — Codex никогда не пишет файлы +- Всегда read-only sandbox — ревьюер никогда не пишет файлы - Максимум 5 раундов для защиты от бесконечных циклов - Показывать пользователю отзывы и правки каждого раунда - Если Codex CLI не установлен или упал — сообщить пользователю: `npm install -g @openai/codex` diff --git a/examples/review-output.md b/examples/review-output.md new file mode 100644 index 0000000..f8a0593 --- /dev/null +++ b/examples/review-output.md @@ -0,0 +1,76 @@ +# Example: Adversarial Code Review Output + +This is a synthetic example showing what a typical adversarial review looks like. + +--- + +## Adversarial Review — Round 1 (mode: code, model: gpt-5.4) + +## Summary + +This change adds a user deletion endpoint to the API. The endpoint accepts +a user ID, deletes the user record, and returns 204. The implementation +handles the happy path correctly but has two significant issues around +data integrity and authorization. + +## Findings + +### [severity: critical] User deletion does not cascade to dependent records + +- **File:** src/api/users.py lines 45-52 +- **What can go wrong:** Deleting a user leaves orphaned records in `orders`, + `sessions`, and `audit_log` tables. Foreign key constraints are set to + `NO ACTION`, so the delete succeeds but dependent data becomes unreferenceable. + Queries joining on `user_id` will silently drop rows. +- **Why vulnerable:** The `delete_user()` function calls + `db.users.delete(user_id)` directly without handling related tables. + No cascade is configured at the database level. +- **Impact:** Data integrity violation. Orphaned orders cannot be attributed + to any user. Financial reconciliation reports will undercount. +- **Recommendation:** Either add `ON DELETE CASCADE` to foreign keys in a + migration, or delete dependent records explicitly in a transaction before + deleting the user. + +### [severity: high] Missing authorization check on delete endpoint + +- **File:** src/api/users.py lines 38-40 +- **What can go wrong:** Any authenticated user can delete any other user + by sending `DELETE /api/users/{id}`. The endpoint checks authentication + (`@require_auth`) but not authorization — there is no admin role check + or ownership validation. +- **Why vulnerable:** The route decorator only has `@require_auth`, not + `@require_role('admin')`. The `user_id` parameter comes from the URL + path and is never compared to the authenticated user's ID. +- **Impact:** Privilege escalation. Any logged-in user can delete + arbitrary accounts including admins. +- **Recommendation:** Add `@require_role('admin')` decorator, or if + self-deletion is intended, verify `request.user.id == user_id`. + +## Verdict + +VERDICT: REVISE + +--- + +### Fixes (Round 1) + +- Added `ON DELETE CASCADE` migration for `orders.user_id` and `sessions.user_id` +- Added `@require_role('admin')` to the delete endpoint +- Added test for unauthorized deletion attempt (returns 403) + +--- + +## Adversarial Review — Round 2 (mode: code, model: gpt-5.4) + +## Summary + +Both critical issues from round 1 are resolved. The cascade migration is correct +and the authorization check is in place. No new issues found. + +## Findings + +No actionable findings. + +## Verdict + +VERDICT: APPROVED