initial site

This commit is contained in:
merrow committed 2026-10-11 22:24:54 +05:00
commit da5b259d06
167 files changed
+34157

No files matched your search

+218
View File
@@ -0,0 +1,218 @@
---
name: fix-finding
description: Исправление и верификация конкретной security-находки в проекте НЕОН (site/crm/db). Использовать, когда пользователь явно просит исправить, закрыть или залечить уязвимость или finding из аудита — «исправь F-3», «закрой находку из AUDIT/FINDINGS.md», «почини IDOR из аудита и проверь». НЕ использовать для обычных багов, рефакторинга, ревью кода/дизайна, полного аудита (полный аудит делает скилл security-audit — он только документирует) или деплоя.
---
# Fix Finding — минимальный проверенный фикс security-находки в НЕОН
Превратить текущую security-находку в минимальный, проверенный на живом стенде
код-фикс. Если код уже безопасен — доказать это и вернуть `no_change`.
Аудит (поиск и документирование) делает скилл `security-audit`; этот скилл —
вторая стадия над его результатами.
## Источник находки
Найди ID и контекст в одном из мест:
- `AUDIT/FINDINGS.md` — вывод аудит-скилла `security-audit`;
- `АУДИТ-ПЕРЕД-РЕЛИЗОМ.md` — предрелизный аудит, нумерация 1–38
(пункт с пометкой «вопрос к владельцу» — не фикси, это `blocked`);
- F-N — сквозная нумерация security-фиксов в комментариях кода
(`docker-compose.yml`, `crm/server.py`) и в `crm/_security_smoke.mjs`;
- прямое описание от пользователя (файл/эндпоинт + путь атаки).
Если в находке нет файла/эндпоинта — сначала локализуй путь атаки по коду.
Фиксить можно только явно запрошенную находку; соседние находки — доложить,
не чинить.
## Порядок свойств результата
Оценивай результат в этом порядке; более раннее никогда не меняется на более
позднее. «Минимальный» = наименьшее проектно-нативное изменение, закрывающее
все более ранние свойства, а не наименьшее число строк:
1. текущее состояние корректно классифицировано: уязвимо / уже безопасно / недоказано
2. фикс полностью закрывает нарушенную security-границу
3. легитимное поведение и совместимость сохранены
4. проверки проекта (см. гейты ниже) пройдены
5. реализация следует конвенциям проекта
6. патч содержит только необходимый охват
## Карта проекта
- `crm/` — Python 3, stdlib + psycopg, без фреймворков. `server.py` — HTTP +
REST + роли; `notes_api.py` — доски заметок (примешан в Handler);
`storage.py` — PostgreSQL (боевой), `storage_sqlite.py` — dev-двойник
(ограничен: игры/доски/брони/миксы сайта/сброс нумерации → 501);
`js/app.js` + `index.html` + `css/` — панель персонала; `seed/*.json` —
каталог; `migrate/notes_boards.sql` — канонический DDL досок.
- `site/` — React + Vite + Tailwind, собирается в статику под nginx.
`nginx.conf` — edge: лимит `POST /api/orders` (10/мин с IP), real_ip из
X-Forwarded-For, `/media/` отдаёт фото CRM; `src/lib/crm.ts` — мост к API.
- `docker-compose.yml` — site (наружу `127.0.0.1:8080`), crm
(`127.0.0.1:47613`), db (PostgreSQL 17, не публикуется). Секреты только
из `.env`.
- Роли CRM: владелец / администратор / официант / кальянщик — матрица в
README; пять слоёв защиты заказов (nginx-лимит → лимит на гостя →
дедупликация → глобальный тормоз → honeypot).
- Git в проекте НЕТ: перед правкой делай снимок (см. ниже), diff собирай
по снимкам.
Фикс может жить на любом из трёх слоёв (nginx → server.py → storage).
Логика storage продублирована в двух бэкендах: фикс в `storage.py` почти
всегда должен зеркалиться в `storage_sqlite.py` (и наоборот) — аудит не раз
писал «в обоих бэкендах». Учитывай и панель (`crm/js/app.js`): что она
ожидает от изменённого эндпоинта.
## Патч-контракт (до правки)
Изучи саму реализацию, её прямых вызователей, соседние хелперы и разметку
роль×эндпоинт в README. Установи из кода, а не из находки:
- атакующий вход и конкретный путь источник → sink (или сломанный контроль);
- security-инвариант и узкую общую границу, где его enforce;
- легитимное поведение, API-контракты, семантику ошибок, совместимость;
- ближайшие прецеденты в этом же коде (экранирование `esc()` в панели,
параметризованный SQL `%s`, whitelist статики, лимитеры).
Находка — задача о потоке данных и границе, а не о примере входа из отчёта.
Проверь эквивалентные кодировки, alternate-формы парсера, алиасы, всех
вызователей, оба бэкенда и каждую копию security-чувствительного состояния,
которая может обойти фикс. Небезопасное состояние обрабатывай явно — не
принимай, не обрезай и не переинтерпретируй его молча.
## Предпатчевое расследование
До правки запусти один свежий read-only субагент (Agent tool, general-purpose,
с инструкцией не менять файлы). Если делегирование недоступно — сделай тот же
проход сам отдельно, свежим взглядом:
- **Исследователь границы и совместимости:** независимо трассирует путь
источник → sink, находит общую границу enforcement, затронутые входы,
альтернативные представления и состояния, переходы валидация →
использование, конкретные sibling-пути и обходы. Фиксирует легитимные
сценарии и публичное поведение, которые обязаны остаться, и проверяет
вызователей, режимы, ошибки, побочные эффекты, конвенции, готовые хелперы
и применимые команды проверки.
Расследование требует ссылок на файлы/строки проекта и разделения фактов,
выводов и открытых вопросов. По завершении сверь с собственной трассировкой
и выбери границу фикса.
## Снимки вместо git
Перед первым изменением скопируй оригиналы изменяемых файлов в
`AUDIT/FIXES/.snapshots/<ID>/` (создай каталог). По снимкам собери diff для
ревью и отчёта (PowerShell `Compare-Object`, `fc` или `git diff --no-index`,
если git есть на хосте). Не оставляй временных файлов-двойников вида `.bak`
в рабочем дереве после завершения.
## Реализация
1. Протрассируй путь и верни `no_change`, если код уже безопасен — без
спекулятивных правок.
2. Где возможно, прогони через границу минимальный высокосигнальный repro
и один легитимный контрольный запрос по тому же пути (живой стенд ниже).
3. Сделай наименьший фикс на общей границе. Предпочитай соседние хелперы и
установленные API. Не расширяйся на редизайн, уборку и соседние находки.
4. До верификации атакуй свой патч, а не защищай: проверь каждого прямого
вызователя изменённого хелпера и обе ветки каждого изменённого условия.
Найди (а) один sibling-путь, представление или копию, которые всё ещё
доходят до sink, (б) один обычный/дефолтный вход, который патч начал
отвергать или переинтерпретировать. Если хоть одно есть — переделай.
5. Верифицируй по гейтам (порядок обязателен).
## Гейты верификации
1. **Синтаксис/сборка** — только изменённое:
- Python: `python -m py_compile crm\server.py crm\storage.py crm\storage_sqlite.py crm\notes_api.py` (в crm/);
- сайт (если тронут `site/`): из `site/` — `npx tsc --noEmit`, затем `npm run build`;
- движок миксов (если тронут `site/src` миксы/стоп-лист): `npm run test:engine`.
2. **Security-триггер** — repro находки на живом стенде больше не
воспроизводится + один альтернативный класс вредоносного входа.
3. **Легитимный контроль** — обычный сценарий по тому же пути работает;
соседние роли не сломаны (токены owner/admin/waiter — матрица в README).
### Живой стенд
- **Postgres-стек** (нужен для игр, досок, броней, миксов, сброса нумерации —
в sqlite это 501): `docker compose up -d --build`, CRM на
`127.0.0.1:47613`, сайт на `127.0.0.1:8080`.
- **SQLite-стенд** без Docker: `start-crm.bat` (`CRM_DB=sqlite`,
`CRM_ALLOW_DEFAULT_PASSWORDS=1`, порт 47613).
- Сайт-дев: в `site/` `npm run dev`; если docker уже держит 8080 —
`npm run dev -- --port 8090 --strictPort`.
- Перед стартом проверь, кто слушает порт (`netstat -ano | findstr :47613`):
8080/47613 держит docker-стек, **8081 — чужой процесс, его не трогать**.
- Доступы стенда — из `.env` (SMOKE_* нет в .env — задавай при запуске скрипта).
### Регрессионный артефакт
Проект верифицирует фиксы smoke-скриптами по образцу `crm/_security_smoke.mjs`:
`fetch` против `127.0.0.1:47613`, PASS/FAIL, ненулевой exit при провале,
пароли через env (`SMOKE_OWNER_PW`, `SMOKE_WAITER_PW`). Добавь проверки
фикса в `_security_smoke.mjs` или создай сфокусированный `crm/_fix_<ID>.mjs`
по тому же образцу. Помни побочные эффекты: lockout-тест закрывает
`waiter.mark` на 15 минут (порядок проверок важен), тест смены пароля обязан
возвращать пароль обратно.
## Ревью кандидата
После реализации и фокусных проверок запусти одного свежего read-only
субагента (Agent tool; инструкции не редактировать и не делегировать). Дай
ему только находку, корень проекта, авторизованный объём, конвенции и текущий
diff кандидата — без обоснований, отчёта исследователя и заявлений, что
тесты прошли. Если делегирование недоступно — сделай этот проход сам,
отдельно, до финальной верификации:
- **Ревьюер обходов и регрессий:** реконструирует инвариант и ищет конкретный
выживший маршрут через затронутые входы, эквивалентные представления,
границы парсеров, алиасы, оба бэкенда, слой nginx и щели
валидация → использование; трассирует изменённые условия и вызователей на
предмет конкретной поломки легитимных входов, контрактов, ошибок,
побочных эффектов и конвенций.
Находки ревьюера — гипотезы: подтверждай их по коду или фокусным запуском,
правь только подтверждённые в рамках находки и совместимости. Затем
прогони затронутые гейты заново и убедись, что временных и посторонних
изменений не осталось. Только один цикл ревью.
Верни `blocked`, если находка может быть реальной, но не хватает существенных
данных, инструментария, доступа или это продуктовое решение владельца
(пример: №38 «waiter вне смены видит телефоны» из предрелизного аудита) —
тогда безопасный фикс невозможно завершить или проверить.
## Отчёт
Напиши `AUDIT/FIXES/<ID>.md` и проставь в источнике находки (`AUDIT/FINDINGS.md`
или `АУДИТ-ПЕРЕД-РЕЛИЗОМ.md`) статус фикса со ссылкой на отчёт. В финальном
ответе в чате обязательно:
- outcome: `fixed` / `no_change` / `blocked`
- конкретный уязвимый путь, security-инвариант и легитимное поведение, которое
обязано было сохраниться
- выбранная стратегия и почему это самый узкий полный вариант (либо — какое
решение владельца отсутствует при `blocked`)
- изменённые файлы и добавленные тесты/артефакты
- команды по гейтам с результатами pass/fail/unknown
- как показано, что исходная находка больше не воспроизводится
- как показано, что легитимное поведение сохранилось
- оставшиеся пробелы и пропущенные проверки, если есть
## Жёсткие правила
- Не докладывай `fixed`, пока не пройдены все гейты по порядку. Проверку
можно пропустить только с обоснованием по коду; недоступная существенная
проверка = `blocked` и явное указание, чего не хватило.
- Не полагайся только на чтение кода, когда возможен фокусный repro на стенде.
- Не расширяй патч на уборку, соседние находки и редизайн без доказательства,
что без этого граница не закрывается.
- Не удаляй и не затирай правки пользователя — git нет, снимки единственная
страховка; не трогай `crm/data/`, `crm/media/`, `.env` и `site/dist`.
- Не ослабляй авторизацию, ролевую матрицу, пять слоёв защиты заказов,
валидацию входа, fail-fast на дефолтных паролях и лимитеры ради зелёных
проверок.
- Не деплой на прод (`docker compose up -d --build site crm`) без явной
команды владельца — верификация идёт на локальном стенде.
- Не прячь пробелы доказательств: если среда не дала проверить — назови
команду и чего не хватает.
File diff suppressed because it is too large. Load diff