Skip to content
SENS Platform Docs

Dependency Policy

Dependencies must support self-hosted operation, commercial use, and future customer-owned on-premise Kubernetes deployments.

This policy applies to runtime dependencies, development dependencies, build tooling, generated artifacts, and optional integrations.

Runtime dependencies are packaged with applications or required for production operation. They need explicit review for:

  • license compatibility with commercial use and redistribution,
  • self-hosted and on-premise operation,
  • required external services,
  • operational ownership,
  • security update path,
  • replacement strategy when the dependency is adapter-facing.

Development dependencies are used for local checks, CI, tests, documentation, or build tooling. They still need license review, but they must not become required runtime services.

Optional proprietary integrations must be isolated behind adapters and must not be required for core platform operation.

Allowed by default after review:

  • MIT,
  • Apache-2.0,
  • BSD-2-Clause,
  • BSD-3-Clause,
  • ISC.

Requires explicit review before adoption:

  • LGPL,
  • MPL,
  • EPL,
  • AGPL,
  • GPL,
  • custom or source-available licenses,
  • licenses with field-of-use, SaaS, hosting, telemetry, or redistribution restrictions.

Unknown license metadata blocks adoption until clarified.

When adding dependencies, the same change must document:

  • package name and purpose,
  • runtime or development classification,
  • license,
  • whether the dependency requires a proprietary service,
  • whether it affects deployment, Helm values, secrets, or environment variables,
  • whether it changes a public or cross-module contract.

Runtime dependencies that affect contracts, configuration, deployment, security, tenancy, persistence, or operations also require matching documentation and tests.

GitHub Dependabot alerts report known vulnerabilities. Dependabot security updates and version-update pull requests are disabled. Keep the alerts enabled when changing the repository security settings.

Renovate scans package manifests, GitHub Actions, Dockerfiles, and Docker Compose files. It records available updates in the Dependency updates GitHub Issue. An update becomes actionable after a minimum release age of seven days.

The dashboard is the update backlog. To implement an update manually, create a branch from the current default branch and open a pull request with the manifest, lockfile, code, test, and documentation changes that the update needs. Do not select the dashboard checkbox. Renovate removes the item after the update reaches the default branch.

Select a dashboard checkbox only when Renovate should prepare a routine update pull request. Every routine update requires this explicit approval. Known vulnerabilities bypass dashboard approval so Renovate can create a remediation pull request; Dependabot alerts remain an independent notification source. CI also runs pnpm audit --prod, so a known production vulnerability blocks the change until the dependency graph is patched or an exception is reviewed and documented.

The hosted Mend Renovate GitHub App runs this repository automation. Renovate’s update engine uses the AGPL-3.0-only license. The hosted app is an optional proprietary development service and has no platform runtime or deployment impact. It requires read and write access to repository contents, workflows, issues, pull requests, checks, and commit statuses. It also needs read access to repository administration metadata and Dependabot alerts. The service clones the private repository while a job runs and retains dependency, version, and pull-request metadata. It does not require a repository secret.

Phase 2 adds these root development dependencies:

PackagePurposeLicenseRuntime impact
eslintJavaScript and TypeScript lintingMITNone
@eslint/jsESLint recommended JavaScript rulesMITNone
typescript-eslintESLint support for TypeScriptMITNone
eslint-config-prettierDisable conflicting formatting rulesMITNone
prettierRepository formatting baselineMITNone
prettier-plugin-astroFormat Astro files when presentMITNone
vitestUnit test runnerMITNone
globalsShared ESLint global definitionsMITNone
@types/nodeNode.js type declarationsMITNone

These dependencies are dev-only, do not add production services, do not require secrets, and do not change application behavior.

The documentation image self-hosts its build output and API tools. It does not use a hosted documentation registry or request proxy.

PackagePurposeLicenseRuntime impact
astro, @astrojs/starlightStatic documentation application and content modelMITBuild output served by the existing docs container
starlight-openapiGenerates operation pages from the repository OpenAPI fileMITBuild-time generation only
@scalar/api-reference@1.64.0Interactive OpenAPI reference and browser request clientMITSelf-hosted browser assets in the docs image
starlight-theme-celestiaDocumentation presentation themeMITCSS and static UI assets

Scalar telemetry is disabled, authentication persistence is disabled, and no proxy.scalar.com or other hosted Scalar service is configured. Browser requests go directly to the API server selected from the repository-owned OpenAPI document. The vue-demi install script is approved because Scalar’s self-hosted Vue bundle requires its local compatibility setup; it performs no runtime network or hosted-service integration.

Local development operates the database by default. The explicit ingestion profile also runs the pinned NATS image.

ImagePurposeLicense reviewRuntime impact
timescale/timescaledb:2.28.1-pg17-oss@sha256:…Local PostgreSQL/TimescaleDB databaseTimescaleDB Apache 2 Edition: Apache-2.0Local infrastructure only
nats:2.14.0-alpine3.22@sha256:…Durable raw-ingestion streamApache-2.0Optional local profile and Kubernetes runtime

Image references retain a readable version tag and pin the exact manifest digest. The TimescaleDB image uses the -oss tag so the local default stays on the Apache-2.0 edition. If later work requires TimescaleDB Community features, that must be reviewed and documented as a separate licensing decision.

The Apache-2.0 edition is sufficient for the Phase 3 local database container and for validating connectivity. It does not close the later database decision for automated TimescaleDB retention policies, compression, continuous aggregates, or other features that may require the Timescale License.

NATS JetStream is the active durable stream for Netmore raw ingestion. It is self-hosted, cluster-internal, bounded by stream limits, and replaceable behind the internal raw-event contract. A permanent mock MQTT broker is not part of the target architecture.

Package / imagePurposeLicenseRuntime impact
mqtt@5.15.2MQTT 3.1.1/TLS client and PUBACK backpressure boundaryMITmqtt-ingestion-worker only
@nats-io/jetstream@3.4.0JetStream publish, bootstrap, and pull-consume APIsApache-2.0Both ingestion workers and bootstrap
@nats-io/transport-node@3.4.0Node.js NATS transportApache-2.0Both ingestion workers and bootstrap
@nats-io/nats-core@3.4.0Shared NATS connection types and core protocolApache-2.0Both ingestion workers
nats:2.14.0-alpine3.22@sha256:…Self-hosted single-replica JetStream serverApache-2.0Cluster-internal StatefulSet with PVC
natsio/prometheus-nats-exporter:0.20.1@sha256:…Converts local NATS and JetStream state to Prometheus metricsApache-2.0NATS metrics sidecar only

None requires a proprietary or hosted runtime. Netmore is an optional external provider integration isolated inside the adapter; raw storage and the internal event contract do not depend on its SDK.

Phase 4 adds runtime dependencies for the shared service baseline. They do not require proprietary services and are compatible with self-hosted and future customer-owned Kubernetes deployments.

PackagePurposeLicenseRuntime impact
zodRuntime configuration schema validationMITApplication library, no external service
pinoStructured JSON loggingMITApplication library, no external service
fastifyHealth, readiness, and metrics HTTP endpointsMITApplication library, no external service
prom-clientPrometheus-compatible metrics expositionApache-2.0Application library, no external service

These dependencies affect runtime behavior, configuration validation, logs, metrics, and operation endpoints. They do not add new Helm values yet, do not introduce secrets, do not add persistence, and do not change tenant-owned data paths.

Phase 4.5 adds container packaging, a Helm chart, and GitOps deployment infrastructure for the dedicated Kubernetes test and controlled production environments.

Application container images use node:24-bookworm-slim as the runtime and build base. The image packages the service and its production dependencies only. It must not contain local environment files, SSH keys, Kubernetes credentials, or production secrets.

The Helm chart under infra/helm/sens-platform can deploy embedded infrastructure for the early single-node environments:

ImagePurposeLicense reviewRuntime impact
timescale/timescaledb:2.28.1-pg17-oss@sha256:…PostgreSQL/TimescaleDB StatefulSetTimescaleDB Apache 2 Edition: Apache-2.0Early single-node environments
Argo CDGitOps sync and environment status overviewApache-2.0Cluster operations component
cert-managerACME certificate managementApache-2.0Cluster operations component
TraefikExisting k3s ingress controllerMITExisting cluster ingress component

The chart references Kubernetes Secrets by name and must not render secret values from committed defaults. The dedicated environments use sens-test-timescaledb-auth or sens-production-timescaledb-auth for the embedded TimescaleDB password and ghcr-pull for GHCR image pulls.

CI uses Helm only for rendering and linting. Helm is a deployment validation tool and does not add an application runtime dependency.

The self-hosted secret-management workflow adds these cluster runtime components. All versions are pinned in the infra repository and must be upgraded through a reviewed render, backup, test, and rollback procedure.

Component / imagePurposeLicense reviewScope
OpenBao chart 0.28.6, server 2.6.1KV-v2, audit, Raft storage, auth, and policyMPL-2.0Dedicated openbao namespace
External Secrets Operator chart 2.8.0OpenBao-to-Kubernetes synchronizationApache-2.0Four namespace-scoped controller instances
Stakater Reloader chart 2.2.14Restart on synchronized Secret changesApache-2.0One scoped controller per environment

OpenBao is self-hosted and required for the active secret-management path. Its MPL-2.0 license has been explicitly reviewed for this network service use. Test, Production, and Operations use separate mounts and policies.

The operators are namespace-scoped and do not receive cluster-wide access to Kubernetes Secrets. External Secrets custom resource definitions are installed once through a separate cluster-scoped Argo CD Application. NetworkPolicies restrict ingress to OpenBao and its allowed clients. No component requires a proprietary hosted service.

Phase 6 adds the PostgreSQL repository and migration implementation. These packages run entirely inside the self-hosted application and migration containers and do not require a proprietary service.

PackagePurposeLicenseRuntime impact
pgPostgreSQL connection pool and queriesMITRuntime database adapter
node-pg-migrateVersioned SQL migration executionMITDatabase migration image only
@types/pgTypeScript declarations for the pg packageMITDevelopment and build-time type information

pg is isolated behind @sens-platform/database repositories and connection helpers. node-pg-migrate is packaged into the dedicated database migration image and is not required by long-running service containers. Their deployment configuration and secret handling are documented in the database migration and runtime configuration runbooks.

Phase 7A adds self-contained libraries to platform-api; none requires a hosted or proprietary runtime service.

PackagePurposeLicenseRuntime impact
argon2Native Argon2id password hashing and verificationMITCPU/memory-bounded API operation; native binary packaged in the image
joseHS256 JWT issue and verificationMITIn-process cryptography only
@fastify/cookieHost-only HttpOnly refresh-cookie parsing and serializationMITFastify plugin, no service
@fastify/corsExact-origin browser policy with credentialsMITFastify plugin, no service
@zxcvbn-ts/coreOffline password-strength estimationMITIn-process password validation
@zxcvbn-ts/language-commonLocal common-password dictionaries and graphsMITPackaged static data, no network request
@sens-platform/databaseAuth repositories and PostgreSQL session statePrivate workspace packageExisting self-hosted PostgreSQL dependency

The container build copies and compiles the database workspace package and includes the approved argon2 native build lifecycle. No password, token, or identifier is sent to a third-party service.

The Phase 7A security review also requires patched Fastify transitive runtime versions. The lockfile resolves find-my-way to 9.7.0 or newer and overrides affected fast-uri 3.x/4.x ranges to patched versions within the same major line. These resolutions address the upstream find-my-way HTTP denial-of-service and fast-uri URL host-confusion advisories without adding another runtime component or bypassing the repository’s dependency-age checks.

The visual flow slice adds only self-hostable in-process libraries. No package requires an external proprietary runtime.

PackagePurposeLicenseRuntime impact
@xyflow/reactVisual DAG canvas and port interactionsMITBrowser bundle only
quickjs-emscriptenIsolated custom-script JavaScript runtimeMITWASM inside the dedicated sandbox worker
handlebarsStrict tenant e-mail template renderingMITAction worker with an explicit helper allowlist
sanitize-htmlSanitizes rendered e-mail HTMLMITAction worker only
nodemailerSMTP adapterMIT-0Action worker only; no hosted service required
axllent/mailpit:v1.27.8@sha256:…Optional local SMTP sink and inspection UIMITCompose actions profile only; never Helm

React Flow does not send telemetry. The QuickJS adapter is isolated behind the sandbox request contract and hardened by process and Pod boundaries. Its use is not a claim of a complete security audit; the documented review remains a mandatory production gate. Custom-script editing was outside the initial slice; the completion adds Monaco as direct ESM modules with local workers and no CDN; script source is never executed in the browser. Mailpit is a fixed local-development image and is not a core runtime dependency or production deployment component.

apps/web-console uses only self-hosted browser and build dependencies. None sends telemetry or requires a hosted service.

Package / toolPurposeLicenseRuntime impact
react, react-domPermanent platform web consoleMITBrowser bundle only
react-router ^8.3.0Declarative, hash-free browser routingMITBrowser bundle only; no hosted service
viteStatic production build and local dev serverMITBuild/development only
@vitejs/plugin-react-swcReact transform through SWCMITBuild/development only
@swc/coreNative SWC compiler used by the Vite pluginApache-2.0Approved install script; absent from runtime image
Testing Library packagesAccessible component interaction testsMITTest only
happy-domBrowser DOM implementation for unit testsMITTest only
class-variance-authorityTyped component variantsApache-2.0Browser bundle only
clsx, tailwind-mergeDeterministic class compositionMITBrowser bundle only
lucide-reactTree-shakeable interface iconsISCBrowser bundle only
Direct Radix primitive packagesAccessible shadcn interaction and composition primitivesMITBrowser bundle only; no aggregate runtime barrel
tailwindcss, @tailwindcss/viteshadcn-compatible token utilities and build integrationMITBuild/development only
tw-animate-cssReduced-motion-compatible utility definitionsMITBuild/development only
@xyflow/reactTyped visual telemetry-flow canvasMITBrowser bundle only
monaco-editor 0.56.0Custom TypeScript source editor and local language workerMITLazy Scripts-view browser chunk; no CDN
@sentry/node, @sentry/reactOptional sanitized error and performance reportingMITNo-op when disabled; optional EU SaaS
@sentry/vite-pluginCI source-map upload and deletionMITBuild only; token never enters runtime
posthog-jsConsent-based fixed product eventsMITBrowser only, Production flag, dynamically loaded
axe-coreAutomated accessibility assertionsMPL-2.0Test only; absent from runtime image

The final container contains only Node.js, the built static assets, and the dependency-free runtime server. Runtime configuration is injected when the container starts and is not baked into the browser bundle.

React Router 8 requires Node.js >=22.22.0 for development and builds. CI and container builds use the pinned Node.js 24 Active LTS line. Dependabot may update that line, but a new Node.js major is adopted only through an explicit migration after it reaches Active LTS. Routing remains client-side; no additional runtime service, environment variable, Ingress rule, or Helm value is required.