From 8897bd9585004b89e4347712c33bd91867c50015 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Mon, 24 Aug 2026 11:21:28 +0300 Subject: [PATCH] docs(specs): archive dependency hygiene remediation --- .../.openspec.yaml | 2 + .../design.md | 188 ++++++++++++++++++ .../proposal.md | 50 +++++ .../specs/workspace-artifact-hygiene/spec.md | 55 +++++ .../tasks.md | 63 ++++++ .../specs/workspace-artifact-hygiene/spec.md | 57 ++++++ 6 files changed, 415 insertions(+) create mode 100644 openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/.openspec.yaml create mode 100644 openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/design.md create mode 100644 openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/proposal.md create mode 100644 openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/specs/workspace-artifact-hygiene/spec.md create mode 100644 openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/tasks.md create mode 100644 openspec/specs/workspace-artifact-hygiene/spec.md diff --git a/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/.openspec.yaml b/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/.openspec.yaml new file mode 100644 index 0000000..4102db8 --- /dev/null +++ b/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-08-24 diff --git a/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/design.md b/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/design.md new file mode 100644 index 0000000..927cd4d --- /dev/null +++ b/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/design.md @@ -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 ``, 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 не требуются. diff --git a/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/proposal.md b/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/proposal.md new file mode 100644 index 0000000..58b8adf --- /dev/null +++ b/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/proposal.md @@ -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. diff --git a/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/specs/workspace-artifact-hygiene/spec.md b/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/specs/workspace-artifact-hygiene/spec.md new file mode 100644 index 0000000..fc4a45c --- /dev/null +++ b/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/specs/workspace-artifact-hygiene/spec.md @@ -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 diff --git a/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/tasks.md b/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/tasks.md new file mode 100644 index 0000000..8be9ac3 --- /dev/null +++ b/openspec/changes/archive/2026-08-24-address-dependency-advisories-and-repo-hygiene/tasks.md @@ -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 никогда не содержал незавершённую работу. diff --git a/openspec/specs/workspace-artifact-hygiene/spec.md b/openspec/specs/workspace-artifact-hygiene/spec.md new file mode 100644 index 0000000..f27fe50 --- /dev/null +++ b/openspec/specs/workspace-artifact-hygiene/spec.md @@ -0,0 +1,57 @@ +# workspace-artifact-hygiene Specification + +## Purpose + +Определяет проверяемые границы для dependency advisories, локальной +configuration и SQLite runtime-артефактов независимых репозиториев WealthLedger. + +## 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