Refactor: rename user secrets table to custom secrets (#11525)

Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
Rohit Malhotra
2025-10-27 12:58:07 -04:00
committed by GitHub
parent 26c636d63e
commit eb616dfae4
34 changed files with 180 additions and 143 deletions

View File

@@ -23,7 +23,7 @@ from openhands.integrations.provider import (
from openhands.integrations.service_types import ProviderType
class UserSecrets(BaseModel):
class Secrets(BaseModel):
provider_tokens: PROVIDER_TOKEN_TYPE_WITH_JSON_SCHEMA = Field(
default_factory=lambda: MappingProxyType({})
)
@@ -96,7 +96,7 @@ class UserSecrets(BaseModel):
) -> dict[str, MappingProxyType | None]:
"""Custom deserializer to convert dictionary into MappingProxyType"""
if not isinstance(data, dict):
raise ValueError('UserSecrets must be initialized with a dictionary')
raise ValueError('Secrets must be initialized with a dictionary')
new_data: dict[str, MappingProxyType | None] = {}

View File

@@ -14,7 +14,7 @@ from pydantic import (
from openhands.core.config.llm_config import LLMConfig
from openhands.core.config.mcp_config import MCPConfig
from openhands.core.config.utils import load_openhands_config
from openhands.storage.data_models.user_secrets import UserSecrets
from openhands.storage.data_models.secrets import Secrets
class Settings(BaseModel):
@@ -30,7 +30,7 @@ class Settings(BaseModel):
llm_base_url: str | None = None
remote_runtime_resource_factor: int | None = None
# Planned to be removed from settings
secrets_store: UserSecrets = Field(default_factory=UserSecrets, frozen=True)
secrets_store: Secrets = Field(default_factory=Secrets, frozen=True)
enable_default_condenser: bool = True
enable_sound_notifications: bool = False
enable_proactive_conversation_starters: bool = True
@@ -76,7 +76,7 @@ class Settings(BaseModel):
@model_validator(mode='before')
@classmethod
def convert_provider_tokens(cls, data: dict | object) -> dict | object:
"""Convert provider tokens from JSON format to UserSecrets format."""
"""Convert provider tokens from JSON format to Secrets format."""
if not isinstance(data, dict):
return data
@@ -87,10 +87,10 @@ class Settings(BaseModel):
custom_secrets = secrets_store.get('custom_secrets')
tokens = secrets_store.get('provider_tokens')
secret_store = UserSecrets(provider_tokens={}, custom_secrets={}) # type: ignore[arg-type]
secret_store = Secrets(provider_tokens={}, custom_secrets={}) # type: ignore[arg-type]
if isinstance(tokens, dict):
converted_store = UserSecrets(provider_tokens=tokens) # type: ignore[arg-type]
converted_store = Secrets(provider_tokens=tokens) # type: ignore[arg-type]
secret_store = secret_store.model_copy(
update={'provider_tokens': converted_store.provider_tokens}
)
@@ -98,7 +98,7 @@ class Settings(BaseModel):
secret_store.model_copy(update={'provider_tokens': tokens})
if isinstance(custom_secrets, dict):
converted_store = UserSecrets(custom_secrets=custom_secrets) # type: ignore[arg-type]
converted_store = Secrets(custom_secrets=custom_secrets) # type: ignore[arg-type]
secret_store = secret_store.model_copy(
update={'custom_secrets': converted_store.custom_secrets}
)
@@ -119,7 +119,7 @@ class Settings(BaseModel):
return v
@field_serializer('secrets_store')
def secrets_store_serializer(self, secrets: UserSecrets, info: SerializationInfo):
def secrets_store_serializer(self, secrets: Secrets, info: SerializationInfo):
"""Custom serializer for secrets store."""
"""Force invalidate secret store"""
return {'provider_tokens': {}}

View File

@@ -5,7 +5,7 @@ from dataclasses import dataclass
from openhands.core.config.openhands_config import OpenHandsConfig
from openhands.storage import get_file_store
from openhands.storage.data_models.user_secrets import UserSecrets
from openhands.storage.data_models.secrets import Secrets
from openhands.storage.files import FileStore
from openhands.storage.secrets.secrets_store import SecretsStore
from openhands.utils.async_utils import call_sync_from_async
@@ -16,7 +16,7 @@ class FileSecretsStore(SecretsStore):
file_store: FileStore
path: str = 'secrets.json'
async def load(self) -> UserSecrets | None:
async def load(self) -> Secrets | None:
try:
json_str = await call_sync_from_async(self.file_store.read, self.path)
kwargs = json.loads(json_str)
@@ -26,12 +26,12 @@ class FileSecretsStore(SecretsStore):
if v.get('token')
}
kwargs['provider_tokens'] = provider_tokens
secrets = UserSecrets(**kwargs)
secrets = Secrets(**kwargs)
return secrets
except FileNotFoundError:
return None
async def store(self, secrets: UserSecrets) -> None:
async def store(self, secrets: Secrets) -> None:
json_str = secrets.model_dump_json(context={'expose_secrets': True})
await call_sync_from_async(self.file_store.write, self.path, json_str)

View File

@@ -3,7 +3,7 @@ from __future__ import annotations
from abc import ABC, abstractmethod
from openhands.core.config.openhands_config import OpenHandsConfig
from openhands.storage.data_models.user_secrets import UserSecrets
from openhands.storage.data_models.secrets import Secrets
class SecretsStore(ABC):
@@ -21,11 +21,11 @@ class SecretsStore(ABC):
"""
@abstractmethod
async def load(self) -> UserSecrets | None:
async def load(self) -> Secrets | None:
"""Load secrets."""
@abstractmethod
async def store(self, secrets: UserSecrets) -> None:
async def store(self, secrets: Secrets) -> None:
"""Store secrets."""
@classmethod