SOUP — Software of Unknown Provenance
Inventory of third-party code shipped with the RestartiX Platform, classified by risk and purpose. Required for IEC 62304 (medical device software) compliance and good practice for any GDPR-regulated platform.
What "SOUP" means. Any software not authored by the project team is "of unknown provenance" — even if the source is public, we did not write or fully audit it. Medical device certification requires a documented, risk-classified inventory. Plain dependency lists (
go.mod,package.json) are not sufficient because they don't carry purpose or risk classification.
The authoritative inventory of every byte we ship lives in services/api/go.sum and pnpm-lock.yaml — both checked in. This document is the risk-classified subset focused on direct dependencies (the libraries we deliberately chose to depend on). Indirect / transitive dependencies inherit their risk classification from the parent that pulled them in.
Risk Classification
| Tier | Meaning | Example failure |
|---|---|---|
| Critical | Failure compromises patient safety, data integrity, authentication, or audit. Bug class includes silent data loss, privilege escalation, or memory-safety issues with user-controlled input. | Postgres driver corrupts a write; auth library accepts forged JWT. |
| High | Failure causes feature outage, data leak, or accessibility breach. No direct safety impact, but production SLO and compliance affected. | Redis client misbehaves and rate-limit bypass succeeds; a11y primitive regresses keyboard nav. |
| Standard | Failure causes UI inconvenience or developer-experience regression. No safety, security, or compliance impact. | Icon library renders blank; date formatter localizes wrong month name. |
The AI/ML model columns (Model provider, Model version, Validation status) are populated only for AI/ML model dependencies. They are NULL for libraries — see AI/ML Models below.
Backend Runtime Dependencies
Direct dependencies in services/api/go.mod. Indirect dependencies are inherited and tracked in services/api/go.sum.
| Package | Version | Purpose | Risk | Model provider | Model version | Validation status |
|---|---|---|---|---|---|---|
github.com/aws/aws-sdk-go-v2 | v1.41.6 | AWS SDK base — authentication, request signing, retry logic. Foundation for S3 + future KMS. | Critical | — | — | — |
github.com/aws/aws-sdk-go-v2/config | v1.32.16 | AWS SDK config loading (env, profile, IMDS). | Critical | — | — | — |
github.com/aws/aws-sdk-go-v2/credentials | v1.19.15 | AWS SDK credentials providers (static, env, role assumption). | Critical | — | — | — |
github.com/aws/aws-sdk-go-v2/service/s3 | v1.100.0 | S3 client — patient-data file storage (signatures, documents, forms uploads). See file-storage.md. | Critical | — | — | — |
github.com/aws/aws-sdk-go-v2/service/sesv2 | v1.60.4 | SES v2 client — transactional email transport for the platform notification primitive (1A.18 EmailChannel). Member invites, break-glass alerts, and every future first-party email to a human flows through this. | Critical | — | — | — |
github.com/aws/aws-sdk-go-v2/service/cloudwatch | v1.58.1 | CloudWatch client — read-only GetMetricData for the render-pipeline ops view (media-service CPU/memory utilisation). Console superadmin observability only; no patient data. | Low | — | — | — |
github.com/aws/aws-sdk-go-v2/service/ecs | v1.82.2 | ECS client — read-only DescribeServices for the render-pipeline ops view (media-service running/desired/pending task counts). Observability only. | Low | — | — | — |
github.com/aws/aws-sdk-go-v2/service/applicationautoscaling | v1.41.20 | Application Auto Scaling client — read-only DescribeScalingActivities for the render-pipeline ops view (media-service scale-in/out events). Observability only. | Low | — | — | — |
github.com/clerk/clerk-sdk-go/v2 | v2.5.1 | Clerk auth SDK — JWT verification on every authenticated request. See features/auth/clerk-integration. | Critical | — | — | — |
github.com/go-chi/chi/v5 | v5.2.5 | HTTP router. Every API request passes through chi. | Critical | — | — | — |
github.com/google/uuid | v1.6.0 | UUIDv7 generation. Every primary key in the database. | Critical | — | — | — |
github.com/jackc/pgx/v5 | v5.8.0 | Postgres driver + connection pooling. Sole DB access path. | Critical | — | — | — |
github.com/microcosm-cc/bluemonday | v1.0.27 | HTML sanitiser for clinic-authored booking-page copy (calendars.description_html). The only writer of that column. | Critical | — | — | — |
github.com/redis/go-redis/v9 | v9.18.0 | Redis client — caching, idempotency store, slot holds, rate limiting. | Critical | — | — | — |
github.com/kelseyhightower/envconfig | v1.4.0 | Environment-variable to config struct. Boot-time only. | High | — | — | — |
github.com/oapi-codegen/runtime | v1.4.0 | OpenAPI runtime helpers used by generated types. Types-only generation keeps the runtime surface minimal. | High | — | — | — |
gopkg.in/yaml.v3 | v3.0.1 | YAML parser (OpenAPI spec, tooling). | High | — | — | — |
github.com/lmittmann/tint | v1.1.3 | Colored slog handler for development logs. Production uses the stdlib JSON handler. | Standard | — | — | — |
github.com/testcontainers/testcontainers-go | v0.42.0 | Test-only — base testcontainers API. Used directly to customise the Postgres container with shared_preload_libraries=pg_stat_statements (1A.16). Not in production binary. | Standard | — | — | — |
github.com/testcontainers/testcontainers-go/modules/postgres | v0.42.0 | Test-only — spins up Postgres containers for the RLS integration test harness. Not in production binary. | Standard | — | — | — |
github.com/testcontainers/testcontainers-go/modules/localstack | v0.42.0 | Test-only — spins up LocalStack for the S3 integration test harness. Not in production binary. | Standard | — | — | — |
github.com/testcontainers/testcontainers-go/modules/redis | v0.42.0 | Test-only — spins up Redis containers for the rate-limit integration test harness. Not in production binary. | Standard | — | — | — |
golang.org/x/mod | v0.37.0 | go.mod parser used by cmd/check-soup to enumerate direct Go deps for the SOUP gate. Build-tooling only. | Standard | — | — | — |
golang.org/x/image | v0.44.0 | WebP decoder and the high-quality scaler behind internal/shared/imaging — the normaliser every uploaded image passes through before storage (square-crop, dimension bound, re-encode). Parses attacker-supplied bytes, so a decoder bug is reachable from an unauthenticated-adjacent path; the pixel ceiling is checked from the header before any buffer is allocated to bound the blast radius. | High | — | — | — |
Frontend Runtime Dependencies
Direct dependencies in apps/clinic, apps/portal, apps/console, and packages/ui. Shipped to the browser at runtime. Indirect dependencies tracked in pnpm-lock.yaml.
| Package | Version | Owner | Purpose | Risk | Model provider | Model version | Validation status |
|---|---|---|---|---|---|---|---|
@react-pdf/renderer | ^4.3.0 | clinic | Server-side PDF rendering (F6.2) — turns a pdf_templates block list into a report or medical prescription. Runs in Node via renderToBuffer, never in the browser: the server must produce the bytes it stores as a medical record. Chosen over a headless-Chrome sidecar on measurement (41ms p50 / 31MB vs 193ms / 518MB) and because the legacy report templates port near-verbatim. Romanian diacritics require an explicitly registered font — the built-in fonts drop ș/ț silently. | High | — | — | — |
@daily-co/daily-js | ^0.91.0 | clinic, portal | Browser SDK for video consultations (F5.5). Joins a room with a short-lived, server-minted token — the client never learns a room name and never calls Daily's REST API, which is what stops an appointment identifier from being a key to a live consultation. Used as a CALL OBJECT rather than the prebuilt iframe, because the clinician's call has to sit inside the consultation record rather than in an opaque frame, and because a cross-origin iframe cannot be frame-captured for the posture-grid tool the clinic uses daily. Media is peer-to-peer / SFU with the media server pinned to eu-central-1; recording is off. | Critical | — | — | — |
@clerk/nextjs | ^7.2.5 | clinic, portal, console | Clerk auth integration — sign-in / sign-up / session refresh on every page. | Critical | — | — | — |
@sentry/nextjs | ^10.56.0 | portal | Error / crash monitoring for the patient app — captures client (browser) and server (SSR / route-handler) exceptions to a Sentry EU-region project. Configured GDPR-tight (sendDefaultPii: false, includeLocalVariables: false, URL-token scrubbing in beforeSend, Session Replay error-only + fully masked) so no patient PII egresses. Failure mode that matters is a data leak (error report carrying PII), hence High; an outright SDK outage just loses observability. | High | — | — | — |
| Sentry browser SDK (vendored) | @sentry/browser 7.120.4 bundle.es5.min.js (apps/tv/sentry.min.js) | tv | Error / crash monitoring for the static TV companion (no build step → self-hosted pinned bundle, loaded via <script>; not an npm manifest dep, so the first cell is intentionally non-backticked to stay out of the check-soup manifest gate). Same Sentry EU project family; GDPR-tight (no PII, no replay, URL-token scrubbing). High for the same data-leak reason as @sentry/nextjs. Pin the version in lockstep with the committed sentry.min.js. Must stay an ES5 build — v8+/v10 bundles use ?./??, which Chrome 56 (Tizen 4) can't parse, silently killing all TV error monitoring; v7 bundle.es5.min.js is the newest ES5 line. | High | — | — | — |
next | 16.2.4 | clinic, portal, console | Next.js framework — server components, routing, proxy.ts. | Critical | — | — | — |
react | ^19.2.5 | clinic, portal, console, ui | UI framework. | Critical | — | — | — |
react-dom | ^19.2.5 | clinic, portal, console, ui | React DOM renderer. | Critical | — | — | — |
undici | ^8.2.0 | api-client | HTTP/1.1 client backing Node's fetch() — every server-component / server-action call to the API flows through it. We install a tuned global Agent in each app's instrumentation.ts (keep-alive 30s, 64 connections per origin) to avoid TCP churn at fleet scale. Server-only; not shipped to the browser. | Critical | — | — | — |
hls.js | ^1.6.16 | portal | HLS adaptive-bitrate playback for the patient session exercise player. Consumes Bunny Stream HLS playlists on Chrome / Firefox / Edge / Android Chrome; Safari (iOS + macOS) uses native HLS without this library. Failure means exercise video won't play, blocking the session flow. | High | — | — | — |
radix-ui | ^1.4.3 | ui | Accessibility primitives (dialogs, popovers, dropdowns, listboxes). a11y compliance for forms / clinical UI. | High | — | — | — |
@dnd-kit/core | ^6.3.1 | ui | Drag-and-drop primitive behind the SortableList wrapper (packages/ui) — the sole import site. Powers reorder in the clinic program builder (phases, sessions, exercises). a11y-sensitive: ships a keyboard sensor + live-region announcements so reorder works without a pointer. | High | — | — | — |
@dnd-kit/sortable | ^10.0.0 | ui | Sortable preset for @dnd-kit/core (vertical list reordering) used by SortableList. Same a11y risk surface. | High | — | — | — |
@dnd-kit/utilities | ^3.2.2 | ui | CSS transform helpers for @dnd-kit drag transitions. | High | — | — | — |
@tiptap/react | ^3.29.2 | ui | React bindings for the rich-text editor behind the RichTextEditor wrapper (packages/ui) — the sole import site. Authors tenant-facing copy such as calendars.description_html. Security-relevant: its HTML output is never trusted; internal/shared/richtext sanitises every write server-side, and the editor toolbar is kept in step with that allowlist. | High | — | — | — |
@tiptap/starter-kit | ^3.29.2 | ui | Default node/mark set for @tiptap/react, configured down to the elements the server allowlist accepts (link and horizontal-rule disabled). | High | — | — | — |
@tiptap/extension-underline | ^3.29.2 | ui | Underline mark, not part of starter-kit. Matches leo's toolbar, which clinics use for emphasis in booking copy. | Medium | — | — | — |
zod | ^4.3.6 | ui | Runtime schema validation for forms and inputs. | High | — | — | — |
next-intl | ^4.9.1 | clinic, portal, console | i18n message resolution (en, ro). See i18n.md. | Standard | — | — | — |
@tanstack/react-table | ^8.21.3 | ui | Headless table primitives — Console audit-log table and every Layer 2+ list page. | Standard | — | — | — |
react-day-picker | ^9.14.0 | ui | Calendar component (date filters, future scheduling UI). | Standard | — | — | — |
react-resizable-panels | ^4.12.2 | ui | Resizable split panes — the live-consultation view, where a clinician sizes the consultation record against the video call. | Standard | — | — | — |
lucide-react | ^1.11.0 | clinic, portal, console, ui | Icon set. | Standard | — | — | — |
class-variance-authority | ^0.7.1 | ui | Variant utility for component styling. | Standard | — | — | — |
clsx | ^2.1.1 | ui | Conditional className utility. | Standard | — | — | — |
tailwind-merge | ^3.5.0 | ui | Tailwind class deduplication. | Standard | — | — | — |
date-fns | ^4.1.0 | ui | Date formatting and arithmetic. | Standard | — | — | — |
tw-animate-css | ^1.4.0 | ui | Animation utility classes. | Standard | — | — | — |
sonner | ^2.0.7 | ui | Toast / notification primitive — surfaces action results (saved, deleted, error) across all three apps. Composes with React 19 useActionState server-action flow used everywhere. shadcn's canonical toast since 2024. | Standard | — | — | — |
recharts | ^3.8.1 | clinic | Charting library — adherence sparklines, pain/RPE trend lines, activity histograms on the F9 Phase 2 patient stats tab (/patients/[id]/stats). Pure SVG; no canvas. Will also be consumed by the portal /progress page (L4) without a separate SOUP entry — same package, same risk. Failure renders empty chart areas; stats data still readable in tables. | Standard | — | — | — |
libphonenumber-js | ^1.13.10 | ui | Phone-number parsing, per-country validation and E.164 output — backs the shared PhoneInput used for every phone field (patient profile, emergency contact, clinic locations, F3 form phone fields). Client-side only; the API independently canonicalises to E.164 in internal/shared/phone, so a validation gap here cannot produce a malformed stored number. Failure degrades to an unvalidated text field, never to a bad write. | Standard | — | — | — |
qrcode.react | ^4.2.0 | ui | QR-code rendering — consumed by the share-link mint UI (L10) so clinic staff can hand a phone-scannable QR to a patient at the desk. SVG-based; no canvas dependency. | Standard | — | — | — |
qrcode | ^1.5.4 | portal | Server-side QR string generation for /unsupported, where the route handler can't call react-dom/server (Next 16 Turbopack blocks that import in app-router route handlers). Returns an SVG string we inline into the hand-written HTML. | Standard | — | — | — |
@types/qrcode | ^1.5.5 | portal | TypeScript types for qrcode (the package ships JS only). | Standard | — | — | — |
swr | ^2.4.1 | clinic, ui, portal | Client-owned data cache (P46's canonical client cache). First consumer is the clinic program builder: high-interaction surfaces fetch reads client-side (SWR over clinic route handlers) and apply optimistic mutate() on writes instead of triggering a per-action RSC refresh(). Generalized in packages/ui via the shared useApiResource hook (read cache + revalidate-on-focus/reconnect) for the Portal hybrid, so return navigation is an instant cache hit and data self-refreshes. Writes still go through server actions (auth/RLS/audit). Failure degrades to a stale view + a manual reload; no clinical-safety impact. | Standard | — | — | — |
@mediapipe/tasks-vision | 0.10.35 | portal | Client-side pose-landmark detection (PoseLandmarker, VIDEO running mode) behind the live skeleton overlay on the session "position yourself" step — lets the patient see they're in frame before a session starts. WASM runtime + the .task model are self-hosted under apps/portal/public/mediapipe/ (no CDN, no external runtime fetch); everything runs in-browser and nothing is recorded, stored, or sent. Pulled in via a dynamic import() only on that one screen. Any failure (no WebGL, asset 404, slow device) degrades to the plain mirrored camera and never blocks the flow. Not the F9.1 Class I telemetry pose pipeline — a positioning preview, outside the medical-device boundary. Pinned to an exact version so the committed loader stays in lockstep with the generated WASM. | Standard | Google MediaPipe | pose_landmarker_lite (float16) | Non-clinical — informational overlay only; drives no measurement, rep count, or treatment decision. Not validated for clinical use. |
Build & Tooling
Dependencies used at build, lint, format, typecheck, or doc-generation time. Not shipped to production — failures here cause CI failures, never patient-visible behavior.
This section is included for completeness but classified at a lower bar than runtime deps. Risk is uniformly Standard unless flagged.
| Package | Version | Owner | Purpose | Risk |
|---|---|---|---|---|
typescript | ^6.0.3 | all workspaces | TypeScript compiler. | High — silent miscompilation could produce incorrect bundles. |
turbo | ^2.9.6 | root | Monorepo task orchestrator. | Standard |
@turbo/gen | ^2.9.6 | ui | Code generators for shadcn components. | Standard |
tailwindcss | ^4.2.4 | ui | CSS framework, build-time. | Standard |
@tailwindcss/postcss | ^4.2.4 | ui, all apps | PostCSS plugin for Tailwind. | Standard |
shadcn | ^4.4.0 | ui | shadcn/ui CLI for adding components. Source-imported, not runtime. | Standard |
eslint | ^9.39.4 | all workspaces | Linter. | Standard |
@eslint/js | ^9.39.4 | eslint-config | ESLint base rules. | Standard |
@next/eslint-plugin-next | ^16.2.4 | eslint-config | Next.js linting rules. | Standard |
@typescript-eslint/eslint-plugin | ^8.59.0 | eslint-config | TypeScript-aware lint rules. | Standard |
@typescript-eslint/parser | ^8.59.0 | eslint-config | TypeScript parser for ESLint. | Standard |
typescript-eslint | ^8.59.0 | eslint-config | TypeScript-ESLint umbrella. | Standard |
eslint-config-prettier | ^10.1.8 | eslint-config | Disables ESLint rules that conflict with Prettier. | Standard |
eslint-plugin-only-warn | ^1.2.1 | eslint-config | Convert errors to warnings (non-blocking). | Standard |
eslint-plugin-react | ^7.37.5 | eslint-config | React lint rules. | Standard |
eslint-plugin-react-hooks | ^7.1.1 | eslint-config | React hooks lint rules. | Standard |
eslint-plugin-turbo | ^2.9.6 | eslint-config | Turborepo lint rules. | Standard |
globals | ^17.5.0 | eslint-config | Global identifier definitions for ESLint. | Standard |
prettier | ^3.8.3 | root | Formatter. | Standard |
openapi-typescript | ^7.13.0 | root | OpenAPI → TypeScript codegen for @workspace/api-client. | Standard |
vitepress | ^1.6.3 | docs | Static-site generator for apps/docs/. Not part of any product app. | Standard |
vitest | ^3.2.4 | clinic, portal, console, vitest-config | Component-test runner. Renders client components in jsdom, covering what tsc and next build cannot — they compile a component without executing its render. Not shipped; Next.js builds with Turbopack and never loads Vite. | Standard |
jsdom | ^30.0.1 | clinic, portal, console | DOM implementation the component tests render into. | Standard |
vite | ^5.4.21 | vitest-config | Peer of Vitest, imported only for the UserConfig type in the shared test config. Not a build tool for any app — Next.js compiles with Turbopack. | Standard |
@testing-library/react | ^16.3.2 | clinic, portal, console, vitest-config | React render + query helpers for component tests. | Standard |
@testing-library/jest-dom | ^7.0.0 | clinic, portal, console, vitest-config | DOM matchers (toBeInTheDocument) for component tests. | Standard |
@types/node | ^25.6.0 | all apps, ui | Node types. | Standard |
@types/react | ^19.2.14 | all apps, ui | React types. | Standard |
@types/react-dom | ^19.2.3 | all apps, ui | React DOM types. | Standard |
Container Image Packages
Third-party binaries shipped inside production container images. Not visible to go.mod or package.json, so cmd/check-soup cannot enforce these — they are maintained by hand, and adding an apk add / wget line to a Dockerfile requires a row here in the same PR.
Versions track the base image's package repository unless explicitly pinned; the base image tag is the version anchor.
| Package | Version | Image | Purpose | Risk |
|---|---|---|---|---|
alpine | 3.21 | Dockerfile.api, telemetry, media | Runtime base image. Supplies libc + the package repository every row below resolves against. | Critical — a compromised base image compromises everything running on it. |
postgresql17-client | alpine 3.21 repo | Dockerfile.api | pg_dump for the Layer 2 daily backup (cmd/backup-runner). Major version must be >= the RDS server (17.9) or pg_dump refuses outright. | Critical — this binary produces the artifact that patient-data recovery depends on. A silent corruption here is not detected until a restore is attempted. Mitigated by read-back checksum verification + the documented restore drill. |
openssl | alpine 3.21 repo | Dockerfile.api | AES-256-CBC envelope encryption of the backup artifact (enc -pbkdf2 -iter 100000). Also the decryption tool named in the restore runbook. | Critical — a change in default KDF or cipher behaviour between versions would make existing backups undecryptable. The runner passes every parameter explicitly rather than relying on defaults, specifically to survive that. |
gzip | alpine 3.21 repo | Dockerfile.api | Compression stage of the backup pipeline. | High — a corrupt stream fails the restore, though the read-back checksum catches it at write time. |
golang-migrate | v4.18.1 (pinned) | Dockerfile.api | Schema migration CLI, run by the migrations-runner ECS task. | Critical — applies DDL to the production database. |
AI/ML Models
One AI/ML model ships today, and it is non-clinical: a client-side MediaPipe pose-landmarker that draws a live skeleton on the session "position yourself" step so the patient can confirm they're in frame. It runs entirely in the browser, stores/sends nothing, and drives no measurement or treatment decision (loaded via
@mediapipe/tasks-visionabove). The telemetry pose pipeline (F9.1) — where pose measurements would inform clinical decisions — is a separate, not-yet-shipped concern gated on the Class IIa step, since the registered device declares no measuring function; see Hook 5 of the AI-first ADR.
| Model | Version | Provider | Purpose | Risk | Validation status |
|---|---|---|---|---|---|
| MediaPipe Pose Landmarker (lite) | pose_landmarker_lite float16 / runtime @mediapipe/tasks-vision 0.10.35 | Google MediaPipe | Live in-browser skeleton overlay on the session "position yourself" step (positioning preview — nothing recorded, stored, or sent). Self-hosted model + WASM under apps/portal/public/mediapipe/. | Standard | Non-clinical — informational overlay only; drives no measurement, rep count, or treatment decision. Not validated for clinical use. |
| example | gpt-5 | OpenAI | exercise prescription drafting | Critical | Validated against N=200 manually-reviewed cases — see model-validation/... |
Validation status is the regulatory anchor: every clinical model needs an evidence trail (test set, baseline, error analysis) before it ships. Non-clinical models (e.g. the pose preview above, or a model that summarizes admin emails for staff inboxes) carry a lighter validation bar but still appear here.
Indirect Dependencies
The full transitive dependency graph is in:
- Backend:
services/api/go.sum— every Go module pulled in, with cryptographic hashes - Frontend:
pnpm-lock.yaml(repo root) — every npm package, with integrity hashes
Indirect deps inherit the risk classification of the direct dep that pulled them in. We do not maintain a row for every transitive package because:
- Risk is determined by the call site, not the package. A logger pulled in by an HTTP middleware operates at the same risk tier as the middleware itself.
- The set churns on every
go mod tidy/pnpm install. Maintaining 250+ rows that update arbitrarily is paperwork without signal. - An auditor asking "what code is in this binary?" gets
go.sumandpnpm-lock.yaml. An auditor asking "what risks have you considered?" gets this document.
If a transitive dep ever becomes load-bearing in a way that's surprising — e.g. a CVE that affects us only via an indirect path, or a transitive dep that ends up doing crypto where the parent disclaims it — promote it to a direct dep and add a row here.
Adding a New Dependency
Every new dependency added in any PR must include a SOUP entry in the same PR. The reviewer's job is to confirm the row exists; the contributor's job is to write it.
Procedure:
- Add the dep (
go get,pnpm add, etc.). - Open this file and add a row to the matching table.
- Fill in the columns:
- Version: pin the exact version in your PR (
go.mod/package.json). - Purpose: one sentence — what does it do for us. "It's a Postgres driver" is wrong; "Postgres driver + connection pooling" is right.
- Risk: pick a tier from the classification rubric. When in doubt, pick the higher tier — easier to defend than the lower.
- Model columns: leave em-dashed unless this is an AI/ML model.
- Version: pin the exact version in your PR (
- If the dep is an AI/ML model: also add a row to AI/ML Models with
Model provider,Model version, andValidation status.Validation statuscannot be left blank for a clinical model — the PR is incomplete without it.
Removing a dependency: delete the row. Do not leave deprecated entries — go mod tidy and pnpm install already keep the lock files honest, and stale SOUP rows confuse audits.
Bumping a version: update the version cell in the row. No new row needed unless the upgrade introduces a new risk class (e.g. a logging library adding a network-egress feature would jump from Standard to High).
Maintenance
This document is updated with every dependency change. The make check target runs services/api/cmd/check-soup, which parses every direct dependency in services/api/go.mod and every workspace package.json (dependencies + devDependencies, excluding @workspace/* internals) and asserts each one has a SOUP row, and that no SOUP row points at a removed dep. CI fails when either invariant breaks.
A periodic full audit (every release branch cut, or quarterly minimum) should:
- Confirm every direct dep has a row.
- Spot-check that risk classifications still match how the dep is used.
- Verify versions match what's in lock files.
- Re-run dependency vulnerability scanners (
govulncheck,pnpm audit) and document any waivers here.