MDM — Master Decision Memorandum
Dependency Security Remediation: Three Key Issues
Date: 2026-07-06 · Branch: fix/dependabot-python-sweep · Scope: MIZOKICloudRun
Status: Implemented and verified (this branch) incl. the 2026-07-07 final sweep (Addendum below); merge + CI redeploy pending owner approval.
This MDM records the review of the three proposed solutions for the three key issues identified during the Dependabot remediation sweep (1,561 alerts: 16 critical / 514 high / 630 moderate / 401 low on the default branch), the decisions taken, the code changes, the verification evidence, and the rollback path. It is the single reference for auditors and future agents.
Background
The alert volume was driven by duplication: 128 requirements*.txt files repeat the same
stale pins, plus 6 npm lockfiles (one archived). The base sweep (commits b85fe3b,
7c25491) bumped 54 vulnerable Python pins (152 advisories) to their minimal clearing
versions across 107 files, ran non-breaking npm audit fix on live lockfiles, and removed
an archived 427-package lockfile. Post-sweep OSV re-audit: 3 Python pins remained
flagged, all with no fixed release existing anywhere (pytigergraph==1.4.0,
ray==2.54.0 GHSA-mw35-8rx3-xf9r, two fix-less torch local-DoS advisories).
Three key issues remained. Each had a proposed solution; this MDM reviews and resolves them.
Issue 1 — Dead dependency opa-wasm blocks lockfile regeneration
Problem. Root and services/ekis npm operations failed with
404 GET registry.npmjs.org/opa-wasm — Not found. The package was removed from the npm
registry (superseded by the scoped @open-policy-agent/opa-wasm). Until swapped, neither
lockfile could regenerate, so none of their advisories could ever be fixed.
Root cause (established by investigation, not assumption).
- opa-wasm@^1.9.0 is declared in services/provenance-control-loop/package.json
(@mizoki/provenance-control-loop).
- The repo root is an npm workspace (workspaces: ["services/*", "src/cells/*",
"sdk/*", "apps/*"]), so every root-level npm operation — and operations run inside any
workspace member, including services/ekis — resolves the whole tree and dies on the
dead package. This is why ekis appeared affected despite never declaring it.
- No code anywhere imports opa-wasm (repo-wide grep over js/ts/mjs/cjs: zero hits).
It was a declared-but-unused dependency.
Proposed solution (reviewed): swap to @open-policy-agent/opa-wasm.
Decision: ACCEPTED — zero-risk variant. Because nothing imports it, the swap is a
manifest-only change; no call sites to migrate. The scoped package (1.10.0, latest) is
the same project under its official name.
Implementation.
- services/provenance-control-loop/package.json: "opa-wasm": "^1.9.0" →
"@open-policy-agent/opa-wasm": "^1.10.0".
- Root package-lock.json regenerated (npm install --package-lock-only) — first
successful regeneration since the package died — then npm audit fix
--package-lock-only applied.
- services/ekis/package-lock.json: npm audit fix --package-lock-only
--workspaces=false (workspace mode disabled so it operates on ekis's own lockfile).
Verification. Root npm install --package-lock-only completes; both lockfiles
regenerated with non-breaking audit fixes applied.
Issue 2 — Next.js 14.x carries unpatchable advisories; clean target is 15.5.16
Problem. next@14.0.3 carried 26 advisories (including the middleware
authorization-bypass class) and even latest next@14.2.35 carries 14. OSV analysis of
every advisory affecting 14.2.35: the minimum version clearing all of them is
next@15.5.16 (per-advisory fixed-versions: 15.0.8 → 15.5.16). No 14.x release can
ever be clean.
Affected apps (3 in repo):
| App | Was | Router | Status |
|---|---|---|---|
| services/customer-journey-system/frontend | next 14.0.3, react 18 | App Router | migrated this branch |
| miz-oki-command-center-ui | next ^14.2.32, react 18.3.1 | App Router | deferred — blocked (see below) |
| apps/web | next 16.1.1, react 19.2.3 | — | already clean |
Proposed solution (reviewed): migrate to Next 15 via major upgrade. Decision: ACCEPTED for customer-journey frontend; STAGED (not blind-shipped) for command-center-ui.
Implementation — customer-journey frontend (done, build-verified):
- next 14.0.3 → 15.5.16, react/react-dom ^18.2.0 → ^19.0.0,
@types/react(-dom) → ^19, eslint-config-next → 15.5.16.
- framer-motion ^10 → ^12 (v10's types are incompatible with React 19 types — this was
the only dependency that actually broke).
- src/hooks/useSSE.ts: added explicit types to four custom EventSource
addEventListener callbacks (event: MessageEvent) and setData((prev: any) => …) —
stricter inference under the React 19 type stack; no behavior change.
- Migration risk was pre-checked: the app uses no Next-15 breaking request APIs
(no searchParams/cookies()/headers() usage anywhere in src/app).
Verification. npm run build passes green on Next 15.5.16 / React 19:
✓ Compiled successfully, static prerender of / and /_not-found, First Load JS
298 kB. Lockfile regenerated.
Command-center-ui — why deferred, and the staged plan (decision, not omission).
The production command center uses @react-three/fiber@^8 + @react-three/drei@^9 +
@react-three/postprocessing@^2. fiber 8 is React 18-only; Next 15 App Router
requires React 19; React 19 requires fiber 9 + drei 10 — a real migration chain across
the app's 3D stack, on the UI that serves the canonical login target. Blind-shipping that
without its own CI/visual pass is the wrong risk trade.
Staged plan (follow-up PR): (1) fiber ^9 + drei ^10 + postprocessing ^3, fix render-loop
API changes; (2) react/react-dom ^19 + types; (3) next 15.5.16 + eslint-config-next;
(4) npx @next/codemod@latest upgrade for async-request-API call sites; (5) full build +
visual smoke of the 3D graph views before deploy. Until then it stays on 14.2.35 with the
14 known advisories accepted as documented residual risk.
Issue 3 — High-risk Python bumps needed validation before deploy
Problem. The sweep's riskiest bumps (torch 2.5.1→2.10.0, ray 2.9→2.54, pytest 7/8→9, google-cloud-aiplatform →1.133.0, fastapi 0.139 for the boss agent) were text-only pin changes with no proof the dependency sets still resolve.
Proposed solution (reviewed): smoke-test the bumped sets. Decision: ACCEPTED, strengthened to full-branch coverage. In-session we cannot run 60+ services' test suites, but we CAN prove every changed requirements file still resolves to an installable set — which is exactly the class of failure a blind version sweep introduces. Runtime behavior remains CI's job (see residual risk).
Implementation — resolution validation of all 107 changed files (uv pip compile,
Python 3.11 target). First pass found 17 conflicts; git-bisected against main: 10
introduced by the sweep, 7 pre-existing (already unresolvable before the sweep). All 10
new breaks + 2 easy pre-existing were fixed:
| Conflict class | Files | Fix |
|---|---|---|
google-cloud-aiplatform==1.133.0 needs google-auth>=2.47.0 |
boss v5.x, deployment/boss-agent-pipeline, adk archive | google-auth==2.27.0/2.40.x → 2.47.0 |
aiplatform 1.133 chain (google-genai) needs httpx>=0.28.1 |
boss v5.x, gemini-kg-pipeline, coding_moa, docs/misc, rewoo archive | httpx==0.24–0.26 → 0.28.1 |
fastapi==0.139.0 needs pydantic>=2.9.0 |
boss v5.1–v5.3 | pydantic==2.6.1 → 2.9.2 |
vertexai meta-package is frozen at 1.71.1 and hard-pins vulnerable google-cloud-aiplatform==1.71.1 |
7 files | dropped vertexai where aiplatform is present (aiplatform provides the same import vertexai namespace); replaced with google-cloud-aiplatform==1.133.0 otherwise |
pytest-asyncio 0.23/0.24 caps pytest <8/<9 |
ads-simulator, boss v5.1 | pytest-asyncio → 1.3.0 |
econml==0.14.1 caps scikit-learn <1.3 |
cell13 | econml → 0.16.0 |
ray[default]==2.54.0 needs pydantic ≥2.12 |
cell16 | pydantic==2.5.0 → 2.12.4 |
Verification.
- torch==2.10.0 set (cell03): resolves clean.
- ray[default]==2.54.0 set (cell16): resolves clean after pydantic 2.12.4.
- Boss agent v5.1/v5.2/v5.3 (fastapi 0.139 + starlette 1.3.1 + aiplatform 1.133): all
resolve clean.
- Full re-sweep of the changed files: zero sweep-introduced conflicts remain.
- 5 pre-existing conflicts remain in files that were already unresolvable on main
(archive/…/identity-stitcher-service, miz-oki-command-center-ui/pipelines,
services/ekis/pipelines, services/mizoki-journey-kg/graph-writer,
src/cells/cell03/requirements_graphrag.txt, src/cells/cell25/requirements_cell26.txt)
— not regressions; flagged for their owners.
Residual risk & required follow-ups
- Runtime validation is still CI's job. Resolution-clean ≠ behavior-clean. Highest watch items on redeploy: torch 2.10 (model code), ray 2.54 (API surface), pytest 9 + pytest-asyncio 1.3 (test suites), aiplatform 1.133 (SDK surface), Next 15 app.
- Command-center-ui Next 15 migration — staged plan above; 14 advisories accepted until then.
- Root/ekis npm
--force-class advisories — remaining transitive advisories (axios, handlebars, protobufjs, fastify 4) need per-project breaking bumps through CI. - Pre-existing unresolvable requirement files (5, listed above) — already broken on
main; assign owners. - Dependabot alerts clear only when this branch merges to the default branch.
Rollback
Everything is on fix/dependabot-python-sweep; main is untouched. Full rollback =
don't merge (or git revert the four commits). Per-service rollback = restore that
service's requirements.txt/lockfile from main — changes are file-local; no cross-
service coupling was introduced beyond the version pins themselves.
Decision log (summary)
| # | Decision | Rationale |
|---|---|---|
| 1 | Swap dead opa-wasm → @open-policy-agent/opa-wasm@^1.10.0 |
Official successor; zero imports in code → manifest-only, zero risk |
| 2a | Migrate customer-journey frontend to Next 15.5.16 + React 19 now | Only version line clearing all advisories; app pre-checked (no breaking APIs used); build verified green |
| 2b | Stage (not ship) command-center Next 15 migration | React-three stack (fiber 8) is React-18-only; production login surface deserves its own CI/visual pass |
| 3 | Validate every changed requirements file by resolution, fix all sweep-introduced conflicts | Proves installability branch-wide; distinguishes our breaks (10, all fixed) from pre-existing ones (7, flagged) |
| 4 | Drop frozen vertexai meta-package in favor of google-cloud-aiplatform |
vertexai is permanently pinned to the vulnerable aiplatform 1.71.1; aiplatform ships the same vertexai namespace |
Addendum — 2026-07-07 Final Sweep ("fix all misses")
Every item previously flagged as deferred/residual was re-attacked. Outcomes:
A. Pre-existing unresolvable requirements files — ALL FIXED (6/6)
| File | Root cause | Fix |
|---|---|---|
archive/.../identity-stitcher-service |
google-auth 2.23.4 too old for aiplatform 1.133; httpx 0.25.2; websockets 12.0 vs google-genai (needs >=13,<15.1); py-breaker never existed on PyPI |
google-auth 2.47.0, httpx 0.28.1, websockets 15.0.1, pybreaker==1.4.1 (real package name) |
miz-oki-command-center-ui/pipelines |
apache-beam 2.51.0 caps pyarrow <12 | beam[gcp] 2.72.0 (allows pyarrow <24; NOT 2.74.0 — on py3.11 that line pulls envoy-data-plane 1.0.3 whose betterproto==2.0.0b6 pin was yanked from PyPI), google-cloud-storage 2.19.0 |
services/ekis/pipelines |
same beam/pyarrow cap | same beam 2.72.0 + storage 2.19.0 |
services/mizoki-journey-kg/graph-writer |
google-cloud-pubsub==2.21.6 does not exist |
2.21.5 |
src/cells/cell03/requirements_graphrag.txt |
httpx too old for google-genai chain | httpx 0.28.1 |
src/cells/cell25/requirements_cell26.txt |
causalml 0.14.0 caps sklearn <=1.0.2 | causalml 0.17.0 + scikit-learn 1.6.1 + scipy 1.16.0 + numpy 1.26.4 |
All six now resolve clean (uv, py3.11; pipelines files validated with --prerelease=allow,
matching pip's pinned-prerelease semantics).
B. Command-center-ui Next 15 migration — COMPLETED (the blocker was an illusion)
Investigation overturned the MDM's Issue-2b premise: the React-18-only
@react-three/fiber/drei/postprocessing packages are declared but never
imported — the neural visualization (components/NeuralBrainVisualization.tsx) uses
raw three directly (which was itself undeclared, resolving only transitively!).
Fix: removed the three unused @react-three packages; added three@^0.183.1 (the exact
version the old lockfile already resolved — zero behavior change) + @types/three;
bumped next 15.5.18, react/react-dom ^19, @types/react(-dom) ^19,
eslint-config-next 15.5.18. npm run build green: all 68 routes + middleware.
Zero code changes required.
C. npm advisory closure — 78 → 5 unique vulnerable package@version
- apps/web
next16.1.1 → 16.2.6 (22 advisories incl. HIGH — the earlier "already clean" call was wrong; the first scan's output was truncated). - Both Next 15 apps → 15.5.18 (clears the 1 advisory on 15.5.16).
vitest^2 → ^3.2.6 in provenance-control-loop (CRITICAL GHSA-5xrq-8626-4rwp); also dragsvite5.4.21 (HIGH, fixed only in 6.4.3+) andesbuildto fixed lines.- Scoped
overridesadded per project for transitive fixes: minimatch 9.0.7, fast-uri 3.1.2, postcss 8.5.10, brace-expansion 1.1.13, dompurify 3.4.11 (in-major), uuid ^11.1.1 (GHSA-w5hq-g745-h8pq has no v8/v9/v10 fix); directuuiddeps bumped in ekis + provenance instead (npm EOVERRIDE forbids overriding direct deps). - Operational gotchas recorded for future agents: (1) npm rebuilds a deleted
lockfile FROM the existing
node_modulestree, silently bypassing newoverrides— a true clean regen needsrm -rf node_modules package-lock.json; (2) keyed override specs ("pkg@^9.0.0") were unreliable against nested copies; bare keys applied correctly. - Lockfiles clean-regenerated; both Next apps rebuilt green afterwards (customer-journey 4/4 pages; command-center 68/68).
Final lockfile state: mcp 0 · customer-journey frontend 0 ·
ekis 1 (fastify) · command-center 4 (OTel stack) · root workspace 5 (OTel + fastify).
D. The only remaining items — two coordinated runtime-major migrations (staged)
- OTel JS SDK 2.0 (
@opentelemetry/core2.8.0,sdk-node0.217.0,auto-instrumentations-node0.75.0) in provenance-control-loop + command-center-ui. API-breaking (SDK 2.0 renames/removals in resources, sdk-trace-node, exporters); instrument-touching code must be migrated and validated against a live collector — not blind-shippable from a build alone. - fastify 4 → 5 (+ @fastify/cors ^11, helmet ^13, swagger ^9, swagger-ui ^5) in provenance-control-loop + ekis. Plugin-API changes; needs each service's test suite.
Both are HIGH-severity-carrying but require runtime validation; they are the honest boundary of an in-session sweep. Everything else is closed.