fix(settings): reconcile secret status and model drafts
This commit is contained in:
40
server/tests/test_secret_box.py
Normal file
40
server/tests/test_secret_box.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
|
||||
import pytest
|
||||
|
||||
from app.core import secret_box
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"encoded_key",
|
||||
[
|
||||
"not-valid-base64!",
|
||||
base64.urlsafe_b64encode(b"short-key").decode("ascii"),
|
||||
],
|
||||
)
|
||||
def test_encrypt_rejects_invalid_existing_secret_key(
|
||||
monkeypatch,
|
||||
tmp_path,
|
||||
encoded_key: str,
|
||||
) -> None:
|
||||
key_file = tmp_path / "settings.key"
|
||||
key_file.write_text(encoded_key, encoding="utf-8")
|
||||
monkeypatch.setattr(secret_box, "SECRET_KEY_FILE", key_file)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
secret_box.encrypt_secret("probe")
|
||||
|
||||
assert key_file.read_text(encoding="utf-8") == encoded_key
|
||||
|
||||
|
||||
def test_encrypt_replaces_empty_key_file_with_valid_key(monkeypatch, tmp_path) -> None:
|
||||
key_file = tmp_path / "settings.key"
|
||||
key_file.write_text("", encoding="utf-8")
|
||||
monkeypatch.setattr(secret_box, "SECRET_KEY_FILE", key_file)
|
||||
|
||||
encrypted = secret_box.encrypt_secret("probe")
|
||||
|
||||
assert secret_box.decrypt_secret(encrypted) == "probe"
|
||||
assert len(secret_box.read_secret_key()) == secret_box.KEY_BYTES
|
||||
@@ -123,6 +123,60 @@ def test_blank_secret_input_does_not_clear_saved_secret(monkeypatch) -> None:
|
||||
assert service.load_saved_model_api_key("main") == "persisted-key"
|
||||
|
||||
|
||||
def test_snapshot_marks_undecryptable_model_keys_as_unconfigured(monkeypatch) -> None:
|
||||
temp_dir = build_temp_secret_dir()
|
||||
monkeypatch.setattr(secret_box, "SECRET_KEY_FILE", temp_dir / "settings.key")
|
||||
monkeypatch.setattr(Base.metadata, "create_all", lambda *args, **kwargs: None)
|
||||
monkeypatch.setenv("HERMES_HOME", str(temp_dir / ".hermes"))
|
||||
|
||||
with build_session(temp_dir / "settings.db") as db:
|
||||
service = SettingsService(db)
|
||||
payload = service.get_settings_snapshot().model_dump()
|
||||
payload["llmForm"]["mainApiKey"] = "main-secret"
|
||||
payload["llmForm"]["embeddingApiKey"] = "embedding-secret"
|
||||
payload["llmForm"]["rerankerApiKey"] = "reranker-secret"
|
||||
service.save_settings_snapshot(SettingsWrite(**payload))
|
||||
|
||||
secret_box.SECRET_KEY_FILE.unlink()
|
||||
secret_box.get_or_create_secret_key()
|
||||
|
||||
snapshot = service.get_settings_snapshot()
|
||||
configured_by_slot = {
|
||||
model.slot: model.apiKeyConfigured for model in snapshot.llmForm.models
|
||||
}
|
||||
|
||||
assert snapshot.llmForm.mainApiKeyConfigured is False
|
||||
assert snapshot.llmForm.embeddingApiKeyConfigured is False
|
||||
assert snapshot.llmForm.rerankerApiKeyConfigured is False
|
||||
assert configured_by_slot["main"] is False
|
||||
assert configured_by_slot["embedding"] is False
|
||||
assert configured_by_slot["reranker"] is False
|
||||
|
||||
|
||||
def test_snapshot_does_not_create_missing_secret_key_and_marks_secrets_unconfigured(monkeypatch) -> None:
|
||||
temp_dir = build_temp_secret_dir()
|
||||
monkeypatch.setattr(secret_box, "SECRET_KEY_FILE", temp_dir / "settings.key")
|
||||
monkeypatch.setattr(Base.metadata, "create_all", lambda *args, **kwargs: None)
|
||||
monkeypatch.setenv("HERMES_HOME", str(temp_dir / ".hermes"))
|
||||
|
||||
with build_session(temp_dir / "settings.db") as db:
|
||||
service = SettingsService(db)
|
||||
payload = service.get_settings_snapshot().model_dump()
|
||||
payload["llmForm"]["mainApiKey"] = "main-secret"
|
||||
payload["renderForm"]["jwtSecret"] = "onlyoffice-secret"
|
||||
payload["mailForm"]["password"] = "smtp-secret"
|
||||
service.save_settings_snapshot(SettingsWrite(**payload))
|
||||
|
||||
secret_box.SECRET_KEY_FILE.unlink()
|
||||
|
||||
snapshot = service.get_settings_snapshot()
|
||||
|
||||
assert secret_box.SECRET_KEY_FILE.exists() is False
|
||||
assert snapshot.llmForm.mainApiKeyConfigured is False
|
||||
assert snapshot.renderForm.jwtSecretConfigured is False
|
||||
assert snapshot.mailForm.passwordConfigured is False
|
||||
|
||||
|
||||
def test_runtime_model_config_returns_decrypted_main_model(monkeypatch) -> None:
|
||||
temp_dir = build_temp_secret_dir()
|
||||
monkeypatch.setattr(secret_box, "SECRET_KEY_FILE", temp_dir / "settings.key")
|
||||
|
||||
Reference in New Issue
Block a user