Task card: единая защита Auth-токенов в runtime-логах¶
- Дата: 2026-08-25.
- Статус:
ACCEPTED_FOR_HANDOFF. - Основание: владелец принял принцип, что runtime security-логика должна быть production-ready и одинаковой для DEV, STAGE и будущего PROD.
- Executor: основной агент.
- Verifier: независимые project tester и reviewer.
Цель¶
Заменить временную DEV-only защиту Auth-токенов общей runtime-политикой, которую одинаково наследуют продуктовые контуры DEV, STAGE и PROD без изменения Auth/email контрактов.
Scope¶
Включено¶
- общий Caddy contract для
Referrer-Policy: no-referrerв продуктовых runtime; - общее исключение sensitive Auth callback/reset routes из access logs;
- общий runtime filter URI и
Refererдля success/fail-path; - сохранение API request-log redaction query/path token;
- regression tests и проверка Caddy
2.10.2; - ADR и синхронизация status/plan/task evidence.
Исключено¶
- deploy, server/DNS/runtime mutation, STAGE/PROD promotion;
- commit/push/merge/PR;
- изменение Better Auth, email provider, схемы БД или product permissions;
- чтение секретов и реальные письма.
Критерии приёмки¶
- Все продуктовые edge-site definitions в репозитории импортируют один и тот же
security contract без DEV/STAGE-развилки для
Referrer-Policy. - Sensitive verification/reset API и frontend routes не попадают в access logs ни одного продуктового edge-site definition.
- Edge и app runtime log encoders редактируют query/path token и
Refererдо сериализации, включая upstream fail-path и percent-encoded варианты букв имени query key, которые Auth parser декодирует вtoken. - API logger сохраняет method/status context и редактирует query/path token до сериализации.
- Обычные URL и request context без sensitive token не меняются.
- Политика описана как обязательная для будущего PROD runtime, а не как DEV-only функциональность.
- Focused tests, lint, typecheck, unit/coverage, build, Storybook, OpenAPI,
git diff --checkи оба Caddyfile на Caddy2.10.2успешны. - Независимые tester и reviewer выдают
VERIFIED; только после этого coordinator может присвоитьACCEPTED_FOR_HANDOFF.
Ожидаемые артефакты¶
infra/deploy/Caddyfile.edge,infra/deploy/Caddyfile.app;apps/api/src/logging.ts,apps/api/src/logging.test.tsпри необходимости;- новый ADR и обновлённые task/status/plan/evidence документы;
- матрица
критерий -> доказательство -> результат.
Permissions и блокировка¶
- Локальная реализация и безопасные проверки разрешены принятым решением владельца.
- Любые Git-операции и внешние изменения не разрешены.
- Gate блокируется при расхождении политики между средами, невалидном Caddyfile, регрессии тестов либо невозможности независимо проверить security-критерии.
Пакет доказательств executor¶
Заявленный результат¶
Общая policy решения 0026 реализована локально для обоих фактических Product App edge-block и внутреннего app proxy. Server, Git, DNS, runtime и secrets не менялись.
Матрица приёмки¶
| Критерий | Доказательство | Результат |
|---|---|---|
| Одна policy для App environments | product_app_auth_security импортирован в dev.skuaro.top и legacy App skuaro.top |
PASS |
| Narrow access-log skip | Один snippet с четырьмя sensitive route groups; adapted JSON содержит две log_skip: true policy |
PASS |
| Process/error redaction | Одинаковые URI/Referer filters в edge/app Caddyfile; encoded-key fail-path smoke | PASS_AFTER_FIX |
| API redaction | logging.ts, literal/encoded query-key и path regression tests |
PASS_AFTER_FIX |
| Обычные URL сохраняются | focused negative test | PASS |
| PROD invariant и перенос домена | ADR 0026, architecture и deploy runbook | PASS |
| Обязательные локальные проверки | focused/unit/coverage/static/build/Caddy gates ниже | PASS |
| Независимая проверка | cycle 2 tester и reviewer | VERIFIED |
Выполненные проверки¶
- focused
apps/api/src/logging.test.ts:6/6; - unit:
128/128; - coverage: statements
70.55%, branches67.24%, functions63.29%, lines73.32%; - toolchain, boundaries, lint, typecheck, build, Storybook, OpenAPI и
git diff --check: успешно; - Caddy
2.10.2: edge/appvalidateиadapt --validateуспешно; - adapted edge JSON: две
no-referrerpolicy, двеlog_skip: true, общие URI/Referer filters. - одноразовый Caddy app fail-path:
?to%6ben=<marker>вернул502, process log содержит?to%6ben=REDACTED, marker отсутствует; контейнер удалён.
Пропуски и остаточный риск¶
- E2E/visual не повторялись: локальный browser runtime не использует изменённые Caddyfile, поэтому эти suites не проверяют новый contract.
- Live success/fail-path marker search возможен только после нового зафиксированного
candidate и отдельно разрешённого DEV deploy; до него deploy handoff остаётся
BLOCKED. - Новые Auth token names/routes потребуют одновременного обновления policy и тестов.
Verification cycle 1¶
Tester и reviewer независимо выдали REJECTED: percent-encoded имя query key
to%6ben семантически декодируется Auth parser в token, но первая regex оставляла
marker в API и Caddy fail-path logs. Handoff был запрещён.
Executor расширил API/Caddy redaction на частично и полностью percent-encoded буквы
имени token, добавил regression test и воспроизвёл реальный Caddy 2.10.2
upstream fail-path. Результат был передан в cycle 2.
Verification cycle 2¶
- Tester:
VERIFIED; повторены focused6/6, lint, typecheck, API build, diff-check, Caddy validate/adapt и реальные fail-path markers для literal, partial/full encoded query key, reset path иReferer. - Reviewer:
VERIFIED; все 32 semantic-equivalent partial/full encoding комбинации имениtokenредактируются API serializer, реальные Caddy fail-path markers отсутствуют, архитектурных и документационных противоречий не найдено. - Coordinator: evidence покрывает все критерии текущего локального gate; статус
ACCEPTED_FOR_HANDOFF.
Этот handoff разрешает только подготовку отдельного Git-closeout после команды владельца. Commit, push и DEV deploy не разрешены текущим решением.
Как воспроизвести¶
npx vitest run apps/api/src/logging.test.ts;npm run toolchain:check,boundaries:check,lint,typecheck,test:unit,test:coverage,build,build:storybook,openapi:verify;caddy:2.10.2 caddy validate/adapt --validateдля обоих Caddyfile с синтетическими Basic Auth values;git diff --check.