Merge branch 'fix/encrypt-free-text-and-local-ai' into release/v1.39.3

# Conflicts:
#	src/app/api/import/csv/route.ts
This commit is contained in:
Marc-André Bombeck committed 2026-09-26 21:50:05 +02:00
commit 66b1aef40c
69 files changed
+3625 -367

No files matched your search

+5 -1
View File
@@ -122,9 +122,13 @@
"description": "Optional runtime policy and output tuning for user-configured AI providers. Each variable stands alone and has a safe default when unset.",
"required": false,
"variables": [
{
"name": "AI_PRIVATE_ORIGINS",
"purpose": "AI endpoints on the operator's own network (Ollama, LM Studio, LiteLLM). Comma-separated exact origins (scheme://host[:port]), e.g. \"http://ollama.lan:11434\". Unset, a private AI base URL is refused (apart from what the deprecated ALLOW_LOCAL_AI_PRIVATE_HOSTS=true still covers). Link-local, metadata and unspecified addresses stay refused even when listed; a malformed entry is logged once and grants nothing."
},
{
"name": "ALLOW_LOCAL_AI_PRIVATE_HOSTS",
"purpose": "Local-AI SSRF opt-in. Unset rejects private/internal hosts; set an exact comma-separated host allowlist or \"true\" to allow any private host."
"purpose": "Older form of AI_PRIVATE_ORIGINS, kept for existing installs: an exact comma-separated host list still grants those hosts. \"true\" is deprecated since v1.39.3: it covers only the admin AI key and AI settings saved on an admin account (pinned; metadata and link-local refused), is reported at boot and on the admin AI settings page, and will be removed in a later release."
},
{
"name": "INSIGHTS_MAX_TOKENS",
+22 -1
View File
@@ -418,7 +418,7 @@ async function main() {
}
// ───── Coach (Bytes columns) ─────
// "encryptedContent" "summaryEncrypted" "factEncrypted"
// "encryptedContent" "summaryEncrypted" "titleEncrypted" "factEncrypted"
results.push(
await rotateBytesColumn(
"CoachMessage",
@@ -433,6 +433,16 @@ async function main() {
prisma.coachConversation,
),
);
// v1.39.3 — the conversation title. NULL on a row the free-text backfill
// has not reached yet (its title is still in the readable column), which
// `rotateBytesColumn` skips.
results.push(
await rotateBytesColumn(
"CoachConversation",
"titleEncrypted",
prisma.coachConversation,
),
);
results.push(
await rotateBytesColumn("CoachFact", "factEncrypted", prisma.coachFact),
);
@@ -691,6 +701,17 @@ async function main() {
),
);
// ───── v1.39.3 custom-metric reading note (Bytes column) ─────
// NULL on a reading without a note, and on a row the free-text backfill has
// not reached yet; `rotateBytesColumn` skips both.
results.push(
await rotateBytesColumn(
"CustomMetricEntry",
"noteEncrypted",
prisma.customMetricEntry,
),
);
// ───── v1.38.0 dose free text (Bytes column) ─────
// The note on an administered dose — a reaction, a sore arm. Always
// encrypted on write, so every non-null row rotates.