fix(admin): address Copilot review findings

- Reflect built-in defaults for boolean settings (ALLOW_PRIVATE_URLS
  defaults on) and allow clearing a saved boolean back to default,
  so the SSRF toggle matches actual runtime behavior.
- Harden JSON loading: filter settings values to strings only, and
  schema-validate stored ADMIN_PROVIDERS entries, dropping malformed
  ones instead of letting them reach runtime code.
- Set beforeunload returnValue so the unsaved-changes prompt shows in
  all browsers; reject non-finite numbers in settings validation.
- Fix README/CN/JA docs that claimed the panel auto-generates
  AI_MODELS_CONFIG (providers are merged at read time, not written).
- Add unit tests for corrupted-file value filtering and provider
  schema validation.
This commit is contained in:
dayuan.jiang
2026-06-12 11:34:11 +09:00
parent 3764b9b620
commit f96a0c5a18
15 changed files with 126 additions and 16 deletions

View File

@@ -3,8 +3,10 @@ import os from "os"
import path from "path"
import { afterEach, beforeEach, describe, expect, it } from "vitest"
import {
ADMIN_PROVIDERS_KEY,
adminProvidersToConfig,
deriveEnvUpdates,
loadAdminProviders,
mergeSecrets,
type StoredAdminProvider,
validateAdminProviders,
@@ -328,3 +330,38 @@ describe("validateAdminProviders", () => {
expect(validateAdminProviders(list)).toBeNull()
})
})
describe("loadAdminProviders", () => {
it("returns [] when nothing is stored", () => {
expect(loadAdminProviders()).toEqual([])
})
it("loads valid stored providers", () => {
saveSettings({ [ADMIN_PROVIDERS_KEY]: JSON.stringify([provider()]) })
expect(loadAdminProviders()).toHaveLength(1)
})
it("drops malformed entries and keeps valid ones", () => {
saveSettings({
[ADMIN_PROVIDERS_KEY]: JSON.stringify([
provider({ id: "good" }),
{ id: "missing-fields" }, // no provider/models
{ provider: "openai", models: ["x"] }, // no id
"not-an-object",
]),
})
const loaded = loadAdminProviders()
expect(loaded).toHaveLength(1)
expect(loaded[0].id).toBe("good")
})
it("returns [] when the stored value is not an array", () => {
saveSettings({ [ADMIN_PROVIDERS_KEY]: JSON.stringify({ nope: true }) })
expect(loadAdminProviders()).toEqual([])
})
it("returns [] on invalid JSON", () => {
saveSettings({ [ADMIN_PROVIDERS_KEY]: "{ broken" })
expect(loadAdminProviders()).toEqual([])
})
})

View File

@@ -39,6 +39,31 @@ describe("loadSettings", () => {
)
expect(loadSettings()).toEqual({ TEST_ADMIN_VAR: "abc" })
})
it("drops non-string values from a corrupted file", () => {
fs.writeFileSync(
process.env.SETTINGS_FILE!,
JSON.stringify({
version: 1,
values: {
GOOD: "ok",
NUM: 5,
OBJ: { nested: true },
ARR: [1, 2],
NULL: null,
},
}),
)
expect(loadSettings()).toEqual({ GOOD: "ok" })
})
it("returns empty object when values is null or an array", () => {
fs.writeFileSync(
process.env.SETTINGS_FILE!,
JSON.stringify({ version: 1, values: null }),
)
expect(loadSettings()).toEqual({})
})
})
describe("applyToEnv / saveSettings", () => {