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

@@ -71,8 +71,8 @@ from openhands.server.types import LLMAuthenticationError, MissingSettingsError
from openhands.server.user_auth import (
get_auth_type,
get_provider_tokens,
get_secrets,
get_user_id,
get_user_secrets,
get_user_settings,
get_user_settings_store,
)
@@ -85,8 +85,8 @@ from openhands.storage.data_models.conversation_metadata import (
ConversationTrigger,
)
from openhands.storage.data_models.conversation_status import ConversationStatus
from openhands.storage.data_models.secrets import Secrets
from openhands.storage.data_models.settings import Settings
from openhands.storage.data_models.user_secrets import UserSecrets
from openhands.storage.locations import get_experiment_config_filename
from openhands.storage.settings.settings_store import SettingsStore
from openhands.utils.async_utils import wait_all
@@ -210,7 +210,7 @@ async def new_conversation(
data: InitSessionRequest,
user_id: str = Depends(get_user_id),
provider_tokens: PROVIDER_TOKEN_TYPE = Depends(get_provider_tokens),
user_secrets: UserSecrets = Depends(get_user_secrets),
user_secrets: Secrets = Depends(get_secrets),
auth_type: AuthType | None = Depends(get_auth_type),
) -> ConversationResponse:
"""Initialize a new session or join an existing one.

View File

@@ -14,11 +14,11 @@ from openhands.server.settings import (
)
from openhands.server.user_auth import (
get_provider_tokens,
get_secrets,
get_secrets_store,
get_user_secrets,
)
from openhands.storage.data_models.secrets import Secrets
from openhands.storage.data_models.settings import Settings
from openhands.storage.data_models.user_secrets import UserSecrets
from openhands.storage.secrets.secrets_store import SecretsStore
from openhands.storage.settings.settings_store import SettingsStore
@@ -32,20 +32,18 @@ app = APIRouter(prefix='/api', dependencies=get_dependencies())
async def invalidate_legacy_secrets_store(
settings: Settings, settings_store: SettingsStore, secrets_store: SecretsStore
) -> UserSecrets | None:
) -> Secrets | None:
"""We are moving `secrets_store` (a field from `Settings` object) to its own dedicated store
This function moves the values from Settings to UserSecrets, and deletes the values in Settings
This function moves the values from Settings to Secrets, and deletes the values in Settings
While this function in called multiple times, the migration only ever happens once
"""
if len(settings.secrets_store.provider_tokens.items()) > 0:
user_secrets = UserSecrets(
provider_tokens=settings.secrets_store.provider_tokens
)
user_secrets = Secrets(provider_tokens=settings.secrets_store.provider_tokens)
await secrets_store.store(user_secrets)
# Invalidate old tokens via settings store serializer
invalidated_secrets_settings = settings.model_copy(
update={'secrets_store': UserSecrets()}
update={'secrets_store': Secrets()}
)
await settings_store.store(invalidated_secrets_settings)
@@ -120,7 +118,7 @@ async def store_provider_tokens(
try:
user_secrets = await secrets_store.load()
if not user_secrets:
user_secrets = UserSecrets()
user_secrets = Secrets()
if provider_info.provider_tokens:
existing_providers = [provider for provider in user_secrets.provider_tokens]
@@ -183,7 +181,7 @@ async def unset_provider_tokens(
@app.get('/secrets', response_model=GETCustomSecrets)
async def load_custom_secrets_names(
user_secrets: UserSecrets | None = Depends(get_user_secrets),
user_secrets: Secrets | None = Depends(get_secrets),
) -> GETCustomSecrets | JSONResponse:
try:
if not user_secrets:
@@ -235,8 +233,8 @@ async def create_custom_secret(
description=secret_description or '',
)
# Create a new UserSecrets that preserves provider tokens
updated_user_secrets = UserSecrets(
# Create a new Secrets that preserves provider tokens
updated_user_secrets = Secrets(
custom_secrets=custom_secrets, # type: ignore[arg-type]
provider_tokens=existing_secrets.provider_tokens
if existing_secrets
@@ -290,7 +288,7 @@ async def update_custom_secret(
description=secret_description or '',
)
updated_secrets = UserSecrets(
updated_secrets = Secrets(
custom_secrets=custom_secrets, # type: ignore[arg-type]
provider_tokens=existing_secrets.provider_tokens,
)
@@ -330,8 +328,8 @@ async def delete_custom_secret(
# Remove the secret
custom_secrets.pop(secret_id)
# Create a new UserSecrets that preserves provider tokens and remaining secrets
updated_secrets = UserSecrets(
# Create a new Secrets that preserves provider tokens and remaining secrets
updated_secrets = Secrets(
custom_secrets=custom_secrets, # type: ignore[arg-type]
provider_tokens=existing_secrets.provider_tokens,
)

View File

@@ -27,7 +27,7 @@ from openhands.storage.data_models.conversation_metadata import (
ConversationMetadata,
ConversationTrigger,
)
from openhands.storage.data_models.user_secrets import UserSecrets
from openhands.storage.data_models.secrets import Secrets
from openhands.utils.conversation_summary import get_default_conversation_title
@@ -232,7 +232,7 @@ async def setup_init_conversation_settings(
settings = await settings_store.load()
secrets_store = await SecretsStoreImpl.get_instance(config, user_id)
user_secrets: UserSecrets | None = await secrets_store.load()
user_secrets: Secrets | None = await secrets_store.load()
if not settings:
from socketio.exceptions import ConnectionRefusedError

View File

@@ -30,7 +30,7 @@ from openhands.runtime.base import Runtime
from openhands.runtime.impl.remote.remote_runtime import RemoteRuntime
from openhands.runtime.runtime_status import RuntimeStatus
from openhands.server.services.conversation_stats import ConversationStats
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.utils.async_utils import EXECUTOR, call_sync_from_async
from openhands.utils.shutdown_listener import should_continue
@@ -128,7 +128,7 @@ class AgentSession:
finished = False # For monitoring
runtime_connected = False
restored_state = False
custom_secrets_handler = UserSecrets(
custom_secrets_handler = Secrets(
custom_secrets=custom_secrets if custom_secrets else {} # type: ignore[arg-type]
)
try:
@@ -316,7 +316,7 @@ class AgentSession:
if self.runtime is not None:
raise RuntimeError('Runtime already created')
custom_secrets_handler = UserSecrets(custom_secrets=custom_secrets or {}) # type: ignore[arg-type]
custom_secrets_handler = Secrets(custom_secrets=custom_secrets or {}) # type: ignore[arg-type]
env_vars = custom_secrets_handler.get_env_vars()
self.logger.debug(f'Initializing runtime `{runtime_name}` now...')

View File

@@ -4,7 +4,7 @@ from pydantic import SecretStr
from openhands.integrations.provider import PROVIDER_TOKEN_TYPE
from openhands.server.settings import Settings
from openhands.server.user_auth.user_auth import AuthType, get_user_auth
from openhands.storage.data_models.user_secrets import UserSecrets
from openhands.storage.data_models.secrets import Secrets
from openhands.storage.secrets.secrets_store import SecretsStore
from openhands.storage.settings.settings_store import SettingsStore
@@ -39,9 +39,9 @@ async def get_secrets_store(request: Request) -> SecretsStore:
return secrets_store
async def get_user_secrets(request: Request) -> UserSecrets | None:
async def get_secrets(request: Request) -> Secrets | None:
user_auth = await get_user_auth(request)
user_secrets = await user_auth.get_user_secrets()
user_secrets = await user_auth.get_secrets()
return user_secrets

View File

@@ -7,7 +7,7 @@ from openhands.integrations.provider import PROVIDER_TOKEN_TYPE
from openhands.server import shared
from openhands.server.settings import Settings
from openhands.server.user_auth.user_auth import UserAuth
from openhands.storage.data_models.user_secrets import UserSecrets
from openhands.storage.data_models.secrets import Secrets
from openhands.storage.secrets.secrets_store import SecretsStore
from openhands.storage.settings.settings_store import SettingsStore
@@ -19,7 +19,7 @@ class DefaultUserAuth(UserAuth):
_settings: Settings | None = None
_settings_store: SettingsStore | None = None
_secrets_store: SecretsStore | None = None
_user_secrets: UserSecrets | None = None
_secrets: Secrets | None = None
async def get_user_id(self) -> str | None:
"""The default implementation does not support multi tenancy, so user_id is always None"""
@@ -73,17 +73,17 @@ class DefaultUserAuth(UserAuth):
self._secrets_store = secret_store
return secret_store
async def get_user_secrets(self) -> UserSecrets | None:
user_secrets = self._user_secrets
async def get_secrets(self) -> Secrets | None:
user_secrets = self._secrets
if user_secrets:
return user_secrets
secrets_store = await self.get_secrets_store()
user_secrets = await secrets_store.load()
self._user_secrets = user_secrets
self._secrets = user_secrets
return user_secrets
async def get_provider_tokens(self) -> PROVIDER_TOKEN_TYPE | None:
user_secrets = await self.get_user_secrets()
user_secrets = await self.get_secrets()
if user_secrets is None:
return None
return user_secrets.provider_tokens

View File

@@ -9,7 +9,7 @@ from pydantic import SecretStr
from openhands.integrations.provider import PROVIDER_TOKEN_TYPE
from openhands.server.settings import Settings
from openhands.server.shared import server_config
from openhands.storage.data_models.user_secrets import UserSecrets
from openhands.storage.data_models.secrets import Secrets
from openhands.storage.secrets.secrets_store import SecretsStore
from openhands.storage.settings.settings_store import SettingsStore
from openhands.utils.import_utils import get_impl
@@ -69,7 +69,7 @@ class UserAuth(ABC):
"""Get secrets store"""
@abstractmethod
async def get_user_secrets(self) -> UserSecrets | None:
async def get_secrets(self) -> Secrets | None:
"""Get the user's secrets"""
def get_auth_type(self) -> AuthType | None: