189 lines
12 KiB
Markdown
189 lines
12 KiB
Markdown
## Context
|
||
|
||
См. motivation в `proposal.md`. На старте change frontend напрямую использует
|
||
`react-router@7.9.6`; backend получает `deepmerge-ts@7.1.5` транзитивно через
|
||
`prisma@7.9.1 -> @prisma/config`. Frontend одновременно хранит одинаковые
|
||
`.env` и `.env.example`, а backend хранит пустой tracked `dev.db`; текущий
|
||
backend ignore rule покрывает только `prisma/*.db`.
|
||
|
||
Каждый application directory — отдельный Git repository с собственным
|
||
lockfile. Prisma 7.9.1 также является причиной deferred WL-P2-05, поэтому
|
||
dependency change не может считать e2e gate восстановленным без отдельного
|
||
подтверждения его review trigger.
|
||
|
||
### Baseline 2026-08-24
|
||
|
||
| Область | Наблюдение |
|
||
| --- | --- |
|
||
| Frontend dependency | direct `react-router@7.9.6` |
|
||
| Backend dependency path | `prisma@7.9.1 -> @prisma/config@7.9.1 -> deepmerge-ts@7.1.5`; `@prisma/client` и adapter также `7.9.1` |
|
||
| Frontend environment | `.env` и `.env.example` tracked с одинаковым content; local `.env` не игнорируется |
|
||
| Backend SQLite | пустой root `dev.db` tracked; ignore покрывает только `prisma/*.db` |
|
||
| Local URLs | development template направляет DB в `prisma/dev.db`; e2e config направляет её в `/tmp/wealth-ledger-e2e.db` |
|
||
|
||
### Advisory assessment 2026-08-24
|
||
|
||
`npm audit --omit=dev` reproduces one high frontend finding and three high
|
||
backend findings. The direct frontend path is `react-router@7.9.6`.
|
||
GHSA-2w69-qvjg-hvjx affects React Router `>=7.0.0, <=7.11.0` and is patched
|
||
in `7.12.0`; npm identifies `7.18.2` as the current non-major version that
|
||
also resolves the broader audit result. WealthLedger uses only
|
||
declarative `<BrowserRouter>`, static internal `Link` targets and local
|
||
`navigate` calls. It has no loaders, actions, SSR, RSC, single-fetch or
|
||
prerendering surface. This removes the known preconditions for
|
||
GHSA-2w69-qvjg-hvjx, but does not justify retaining an old direct package:
|
||
the supported fixed version is compatible with Node 22 and React 19 and will
|
||
be adopted.
|
||
|
||
The backend findings resolve through
|
||
`prisma@7.9.1 -> @prisma/config@7.9.1 -> deepmerge-ts@7.1.5`.
|
||
GHSA-ggr8-5vv4-36mx affects deepmerge-ts `<8.0.0` and is patched in `8.0.0`.
|
||
Source code does not import `@prisma/config` or `deepmerge-ts`; the former is
|
||
used by the local Prisma CLI configuration, while runtime uses the generated
|
||
Prisma client and SQLite adapter. The vulnerability requires two
|
||
attacker-controlled recursive object graphs passed into deepmerge APIs, a path
|
||
absent from the delivered HTTP service. npm offers only a Prisma 6.12.0 major
|
||
downgrade and the published latest Prisma remains 7.9.1, so this change
|
||
accepts the tooling-only residual risk rather than forcing an unsupported
|
||
override.
|
||
Review trigger: a vendor-supported Prisma release for the 7.x integration
|
||
that resolves `deepmerge-ts@>=8`, or new evidence that public runtime input
|
||
reaches a deepmerge API.
|
||
|
||
### Implemented dependency outcome
|
||
|
||
`react-router` is upgraded from `7.9.6` to `7.18.2`, its current
|
||
non-major npm audit fix. The existing AppRoutes regression suite validates
|
||
the delivered declarative routing contract after the update, and the frontend
|
||
production dependency audit reports zero findings. The Prisma/deepmerge-ts
|
||
finding is accepted as tooling-only residual risk under the review trigger
|
||
above; no manifest, lockfile or runtime behavior is changed for it.
|
||
|
||
### Implemented hygiene outcome
|
||
|
||
Each application repository exposes a non-mutating `hygiene:check` command.
|
||
The frontend check permits only tracked `.env.example`, requires local
|
||
`.env*` files to be ignored, and is part of `npm run verify`. The backend
|
||
check rejects tracked SQLite runtime files and verifies root/Prisma DB and
|
||
sidecar patterns without treating text fixtures as databases. The redundant
|
||
tracked frontend `.env` and empty backend root `dev.db` are removed; existing
|
||
documented URLs still create development data under ignored `prisma/` and e2e
|
||
data under `/tmp`.
|
||
|
||
### Application-gate evidence
|
||
|
||
Under Node `v22.21.0` and npm `10.9.4`, frontend `npm run verify` passes with
|
||
17 test files / 55 tests after the Router update. Backend `npm ci`,
|
||
`hygiene:check`, non-mutating lint, application/test typechecks and
|
||
`npm test -- --runInBand` pass with 19 suites / 59 tests. `npm run test:e2e`
|
||
still stops during `prisma migrate deploy` with the pre-existing empty
|
||
`Schema engine error` before Jest starts. This is recorded as the WL-P2-05
|
||
deferred outcome, not as a passing e2e result or evidence of a Prisma fix.
|
||
|
||
`npm audit --omit=dev` after the clean install reports zero frontend
|
||
production findings. Backend still reports three high findings in the exact
|
||
Prisma 7.9.1 path recorded above, with only a Prisma 6.12.0 major downgrade as
|
||
an automatic fix. OpenSpec authority, strict change validation, all synced
|
||
spec validation (16/16) and `git diff --check` in every affected repository
|
||
pass.
|
||
|
||
The remediation registry is updated with terminal evidence only after archive.
|
||
It is deliberately not a checkbox in `tasks.md`: the archive lifecycle
|
||
requires every task to be complete before archive, so post-archive bookkeeping
|
||
cannot also be an unfinished implementation task.
|
||
|
||
## Goals / Non-Goals
|
||
|
||
**Goals:**
|
||
|
||
- Получить evidence-based решение по каждому high advisory, а не скрыть его
|
||
массовым обновлением.
|
||
- Применить только минимальные поддерживаемые dependency updates и доказать
|
||
их существующими non-mutating gates.
|
||
- Сделать local environment и SQLite artifacts непригодными для случайного
|
||
commit, не ломая documented bootstrap.
|
||
|
||
**Non-Goals:**
|
||
|
||
- Автоматически обновлять все устаревшие packages, добавлять package manager
|
||
или вводить blanket `overrides` без vendor-supported compatibility path.
|
||
- Менять HTTP/OpenAPI contract, Prisma schema/migrations, production data,
|
||
T-Bank integration или обходить deferred Prisma e2e gate.
|
||
- Создавать CI/CD security scanner, secret-management service или хранить
|
||
реальные секреты в versioned files.
|
||
|
||
## Decisions
|
||
|
||
### Каждый advisory проходит assessment до изменения manifest
|
||
|
||
Для WL-P2-12 сначала фиксируются исходные advisory metadata, installed path,
|
||
affected version range, runtime/build reachability и минимальный supported
|
||
fixed candidate. Затем выбирается один из outcomes: coordinated upgrade,
|
||
accepted risk или deferred risk с конкретным trigger. `npm audit fix --force`
|
||
не используется: он смешивает unrelated upgrades и не создаёт evidence
|
||
применимости.
|
||
|
||
Альтернатива — обновить все findings одной командой audit fix. Она отвергнута,
|
||
потому что Prisma является источником отдельного e2e failure и semver-compatible
|
||
разрешение не доказывает поведение Nest/Prisma integration.
|
||
|
||
### Transitive Prisma finding обновляется только согласованной цепочкой
|
||
|
||
Если assessment требует remediation deepmerge-ts, change обновляет Prisma
|
||
packages только в vendor-supported, lockstep-compatible наборе и проверяет
|
||
фактический resolved graph после чистой установки. Точечный npm override
|
||
транзитивного package допустим только если Prisma официально поддерживает этот
|
||
диапазон; иначе finding остаётся документированным accepted/deferred risk.
|
||
|
||
Альтернатива — принудительно override-ить `deepmerge-ts`. Она отвергнута по
|
||
умолчанию, поскольку обходит ownership dependency chain и может скрыть
|
||
несовместимость Prisma tooling.
|
||
|
||
### Templates versioned, рабочие значения local
|
||
|
||
Frontend сохраняет единственный versioned template `.env.example`; `.env` и
|
||
варианты `.env.*` игнорируются, кроме явно разрешённого example. При удалении
|
||
tracked `.env` его содержимое сначала сверяется с example, поэтому documented
|
||
`cp .env.example .env` остаётся воспроизводимым. Backend `dev.db` удаляется
|
||
только как пустой runtime artifact; ignore policy покрывает root и Prisma
|
||
SQLite locations, не затрагивая будущие намеренно versioned fixtures.
|
||
|
||
Альтернатива — оставить безопасный сегодня `.env` tracked. Она отвергнута:
|
||
Git policy должна предотвращать будущий commit с секретом, а не оценивать
|
||
только текущее значение.
|
||
|
||
### Evidence собирается существующими gates
|
||
|
||
После каждой manifest/lockfile change выполняются `npm ci`, dependency graph и
|
||
relevant audit command в затронутом repository, затем существующие frontend
|
||
`npm run verify` и backend non-mutating lint/typecheck/unit-test gates. Любая
|
||
Prisma-related проверка отдельно сообщает исход `migrate deploy`; её failure
|
||
не маскируется и не переводит WL-P2-05/P2-13 в done.
|
||
|
||
## Risks / Trade-offs
|
||
|
||
- [Минимальный fixed release меняет router behavior или peer resolution] →
|
||
выполнить targeted route/auth regression tests и полный frontend verify до
|
||
принятия lockfile.
|
||
- [Prisma update меняет schema-engine behavior или incompatibly разрешает
|
||
adapter/client packages] → обновлять vendor-supported packages вместе,
|
||
запускать generated/type/unit gates и сохранить фактический e2e outcome.
|
||
- [Ignore rule слишком широка и скрывает fixture] → покрыть только runtime
|
||
DB patterns, проверить tracked files и явно оставить fixtures вне policy.
|
||
- [Удаление tracked `.env` оставляет разработчика без config] → template и
|
||
documented copy command проверяются до удаления tracked файла.
|
||
|
||
## Migration Plan
|
||
|
||
1. Зафиксировать baseline assessments и выбрать outcome для каждого advisory.
|
||
2. Выполнить согласованные dependency/lockfile updates или записать accepted/
|
||
deferred decision с review trigger.
|
||
3. Перевести frontend configuration на `.env.example` + ignore policy;
|
||
удалить tracked runtime inputs из index, сохранив локально воспроизводимый
|
||
file через template.
|
||
4. Удалить пустой backend runtime DB artifact, расширить ignore policy и
|
||
проверить temporary DB location без касания production schema.
|
||
5. Выполнить required gates и, только после archive, добавить terminal
|
||
evidence в remediation registry. Rollback — независимый Git revert в
|
||
затронутом repository; DB migration или user-data recovery не требуются.
|