docs(specs): archive dependency hygiene remediation

This commit is contained in:
2026-08-24 11:21:28 +03:00
parent 9f68ae5255
commit 8897bd9585
6 changed files with 415 additions and 0 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-08-24
@@ -0,0 +1,188 @@
## 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 не требуются.
@@ -0,0 +1,50 @@
## Why
Аудит 20.08.2026 подтвердил high advisories в прямом frontend dependency и
транзитивной Prisma-цепочке, а также две небезопасные практики с локальными
runtime-артефактами: tracked frontend `.env` и tracked пустая SQLite DB. Пока
не проверена применимость advisories и не закреплены безопасные repository
boundaries, следующий локальный bootstrap или автоматическое обновление может
создать security regression либо случайно закоммитить локальные данные.
## What Changes
- Добавить воспроизводимый процесс оценки dependency advisory: зафиксировать
затронутый package path, применимость к архитектуре WealthLedger, выбранное
исправление либо принятое исключение и условие его пересмотра.
- Обновить только подтверждённо безопасные зависимости и lockfiles; не
применять `npm audit fix --force` и не обновлять Prisma вслепую.
- **BREAKING** Убрать tracked `frontend/.env`, оставив versioned
`.env.example`, и исключить рабочие frontend `.env*` из Git с явным
исключением examples.
- **BREAKING** Убрать tracked `backend/dev.db`, запретить runtime SQLite
artifacts во всех поддерживаемых местоположениях и закрепить temporary DB
policy для локальных тестов.
- Обновить remediation registry: пока change активен, он является единственным
active remediation для WL-P2-12, WL-P3-07 и WL-P3-08; completion evidence
добавляется только после archive.
## Capabilities
### New Capabilities
- `workspace-artifact-hygiene`: безопасное обращение с dependency advisories,
локальной configuration и runtime SQLite-артефактами в независимых
frontend/backend Git-репозиториях.
### Modified Capabilities
_Нет._
## Impact
- Frontend: `package.json`, `package-lock.json`, `.gitignore`, tracked
configuration template и regression checks.
- Backend: Prisma dependency graph при подтверждённом исправлении,
`.gitignore`, tracked DB artifact и проверка расположения temporary DB.
- Specs/docs: delta-spec, change design/tasks и актуальный remediation registry.
Не изменяются пользовательские HTTP routes, OpenAPI contract, persisted
production schema, T-Bank integration или deferred Prisma e2e policy. Любое
обновление Prisma обязано отдельно доказать, что не маскирует WL-P2-05 и не
объявляет e2e gate восстановленным без выполнения его review trigger.
@@ -0,0 +1,55 @@
## Purpose
Определяет проверяемые границы для dependency advisories, локальной
configuration и SQLite runtime-артефактов независимых репозиториев WealthLedger.
## ADDED Requirements
### Requirement: Dependency advisory получает проверяемое решение
Для каждого audit-derived dependency advisory система SHALL хранить
проверяемую запись с Audit ID, advisory identifier, затронутой package path и
installed version, оценкой применимости к runtime или build surface и одним из
результатов: исправлено, принято или отложено. Принятое или отложенное решение
MUST содержать rationale и review trigger; исправленное решение MUST содержать
выбранный поддерживаемый upgrade path и evidence воспроизводимой проверки.
#### Scenario: Advisory подтверждён в dependency graph
- **WHEN** проверка находит advisory в direct или transitive package path
- **THEN** remediation record позволяет определить его reachability,
выбранный результат и evidence без применения массового автоматического
обновления зависимостей
#### Scenario: Advisory не применим к delivered architecture
- **WHEN** assessment устанавливает, что advisory не достижим из runtime или
build surface WealthLedger
- **THEN** record фиксирует принятие риска, конкретное rationale и условие
повторной оценки вместо ошибочного заявления об исправлении
### Requirement: Рабочая frontend configuration не является versioned input
Frontend SHALL поставлять versioned `.env.example`, достаточный для создания
локального `.env`, но MUST NOT хранить рабочий `.env` или другой локальный
`.env*` файл в source control. Ignore policy MUST исключать локальные frontend
configuration files, сохраняя явно разрешённый example template.
#### Scenario: Участник создаёт local frontend configuration
- **WHEN** участник копирует `.env.example` в `.env` для запуска frontend
- **THEN** локальный файл доступен runtime, но не появляется среди tracked
файлов Git
### Requirement: Runtime SQLite-данные не являются versioned artifact
Backend MUST NOT хранить SQLite database files, созданные runtime или local
development, в source control. Ignore policy SHALL покрывать поддерживаемые
repository runtime locations, а локальные test/database workflows MUST
направлять временные базы вне source tree и не считать их частью
коммитируемого результата.
#### Scenario: Локальный backend создаёт runtime SQLite database
- **WHEN** backend workflow создаёт SQLite file для development или test run
- **THEN** database находится вне versioned source inputs либо исключена
ignore policy и не появляется среди tracked файлов Git
#### Scenario: В репозитории обнаружен устаревший runtime DB artifact
- **WHEN** tracked SQLite database больше не требуется как fixture или source
input
- **THEN** change удаляет его из source control и сохраняет воспроизводимый
local bootstrap через configuration template и documented workflow
@@ -0,0 +1,63 @@
## 1. Зафиксировать active remediation scope
- [x] 1.1 Обновить `docs/development/audit-remediation.md`: пометить только
WL-P2-12, WL-P3-07 и WL-P3-08 как `active` с
`address-dependency-advisories-and-repo-hygiene`; не менять immutable audit
snapshot и не добавлять terminal evidence до archive.
- [x] 1.2 Подтвердить baseline независимых Git repositories: зафиксировать
installed dependency paths, tracked `.env`/SQLite inputs и существующие
ignore rules без удаления пользовательских local files.
## 2. Принять доказательное решение по dependency advisories
- [x] 2.1 Для React Router и Prisma/deepmerge-ts собрать текущие primary
advisory metadata, affected/fixed ranges, `npm audit` result и reachability
из delivered SPA/backend architecture; записать Audit ID, package path,
runtime/build surface и candidate outcome в change evidence.
- [x] 2.2 Выбрать для React Router минимальный поддерживаемый fixed release
либо accepted/deferred decision с rationale и review trigger; при upgrade
обновить только manifest/lockfile и добавить/скорректировать targeted route
regression coverage, необходимую для обнаружения compatibility regression.
- [x] 2.3 Выбрать для Prisma/deepmerge-ts vendor-supported coordinated upgrade
либо accepted/deferred decision с rationale и review trigger; не применять
blind transitive override или `npm audit fix --force`, а при upgrade сохранить
совместимость `prisma`, `@prisma/client` и adapter packages.
- [x] 2.4 После каждого выбранного upgrade выполнить clean install и
подтвердить фактический resolved dependency graph; не объявлять WL-P2-05 или
WL-P2-13 восстановленными, если их отдельный Prisma trigger не выполнен.
## 3. Защитить local configuration и SQLite artifacts
- [x] 3.1 Добавить frontend hygiene regression check, который допускает только
versioned `.env.example`, подтверждает ignore для local `.env*` и падает,
если рабочая configuration оказывается tracked.
- [x] 3.2 Перевести frontend на `.env.example` как единственный versioned
template: убедиться в эквивалентном bootstrap value, удалить tracked `.env`
из source control и обновить `.gitignore` с явным исключением example.
- [x] 3.3 Добавить backend hygiene regression check для tracked SQLite runtime
artifacts и ignore patterns root/Prisma locations; check не должен скрывать
намеренно versioned text fixtures.
- [x] 3.4 Удалить пустой tracked `backend/dev.db`, расширить backend ignore
policy для SQLite sidecar/runtime files и подтвердить, что documented
development/test DB URLs остаются local или temporary и не требуют
versioned database.
## 4. Верификация и completion evidence
- [x] 4.1 Выполнить affected frontend `npm run verify`, backend non-mutating
`npm run lint`, `npm run typecheck:app`, `npm run typecheck:test` и unit
tests под Node 22; отдельно записать actual Prisma e2e outcome без выдачи
deferred gate за passing.
- [x] 4.2 Выполнить `npm ci` и relevant audit/dependency graph checks в
каждом затронутом application repository, `git diff --check`, strict change
and synced-spec validation с `--store wealth-ledger-specs`, а также OpenSpec
authority verifier; устранить каждый confirmed blocking result.
- [x] 4.3 Провести independent read-only review advisory assessment,
dependency/lockfile diff, hygiene checks, `.env`/SQLite migration и
documentation scope; выполнить applicable `opsx-verify` procedure и
устранить blocking findings до archive.
После archive remediation registry получает terminal evidence: archive path,
commits, exact commands/results, статусы WL-P2-12, WL-P3-07 и WL-P3-08 и ровно
одну следующую рекомендуемую задачу. Это обязательное post-archive действие, а
не task checklist, чтобы archive никогда не содержал незавершённую работу.