Data Sovereignty

Security & Data Sovereignty

askLenny is designed for environments where data cannot leave the network. Here is exactly what does and does not cross your perimeter โ€” and which container is responsible.

๐Ÿ—„๏ธ

Row data: never read by the engine

The Rust graph engine only stores schema metadata. The Python app layer executes SQL and returns results to the browser โ€” no row data is ever stored or forwarded.

๐Ÿ”‘

Passwords: never stored

connectors.yaml references environment variable names only. Actual passwords are injected via Docker Compose and exist only in the app container process memory.

๐Ÿ“ฆ

Graph engine: fully isolated

The Rust engine container has no external network access. It cannot reach your databases, the internet, or any LLM. It responds only to the Python app container.

Container trust boundaries

Frontend Container

:5173

Outbound connections

  • โ†’Python app layer API only

Holds in memory / disk

  • ยทNo credentials
  • ยทNo database access
  • ยทNo persistent storage

App Layer Container

:8000 (loopback)

Outbound connections

  • โ†’Source databases (INFORMATION_SCHEMA + SELECT)
  • โ†’LLM endpoint (configurable)
  • โ†’Rust engine (:3030 internal)

Holds in memory / disk

  • ยทDB credentials (env vars)
  • ยทconnectors.yaml
  • ยทTemporary query results

Graph Engine Container

None

Outbound connections

  • โ†’No external connections whatsoever

Holds in memory / disk

  • ยทSchema graph (.dat files)
  • ยทVector embeddings
  • ยทNo credentials

What leaves your network

Every category of data askLenny handles โ€” where it goes and which container handles it.

DataLeaves network?
Table namesYes โ€” to AI endpoint
Column names + SQL typesYes โ€” to AI endpoint
Natural-language questionYes โ€” to AI endpoint
Schema context (markdown)Yes โ€” to AI endpoint
Row data (SELECT results)Never
Database passwordsNever
Schema graph / embeddingsNever
Query history / resultsNever

Controlling the AI endpoint

Only the Python app container makes LLM calls โ€” for description generation during enrichment and for SQL generation at query time. All other containers are isolated from external networks.

Point LLM_BASE_URL at any OpenAI-compatible server. Use a local model and zero bytes leave your perimeter.

Cloud LLM (default)

GEMINI_API_KEY + remote endpoint

Schema names + questions leave (app container only)

Self-hosted Ollama

LLM_BASE_URL=http://ollama:11434/v1

Zero bytes leave โ€” full on-prem

Private Azure OpenAI

LLM_BASE_URL=https://corp.openai.azure.com

Data stays within your Azure tenant

Network isolation

Exposed ports

  • :5173Frontend dashboard โ€” expose only to internal network or VPN. Never to the public internet.
  • :8000App layer API โ€” bound to 127.0.0.1 by default; browser talks to it via the Compose network.
  • :3030Rust engine โ€” NOT exposed. Accessible only from the app container over the internal Docker bridge.

askLenny never calls home

  • โœ“No telemetry or usage reporting
  • โœ“No licence check or phone-home
  • โœ“No package downloads at runtime โ€” all dependencies in the image
  • โœ“MIT licensed โ€” audit the source code on GitHub

Known limitations

Being honest about what askLenny does not currently do.

โš 

No dashboard authentication

The web UI on port 5173 has no login screen. Run it behind a VPN, internal network boundary, or a reverse proxy with auth. Do not expose it to the public internet.

โš 

No application-layer encryption at rest

The .dat files in the engine volume are unencrypted binary. Apply host-level disk encryption (BitLocker, LUKS) if required by your policy.

โš 

AI provider privacy policy applies

When using a cloud LLM (Gemini, OpenAI, etc.), your schema names and questions are subject to that provider's data terms. Use a self-hosted model to eliminate this entirely.

โš 

SQL execution uses the read account

The same database account used for INFORMATION_SCHEMA discovery also executes user queries. Scope permissions to SELECT on the tables you want queryable.