mirror of
https://github.com/lfnovo/open-notebook.git
synced 2026-05-04 22:30:36 +00:00
fix: handle credential decryption errors gracefully (#740)
- Credential.get_all() now uses per-row error handling instead of failing on first bad row - Broken credentials include decryption_error field with descriptive message - DELETE endpoint falls back to direct DB delete when credential can't be decrypted - Frontend shows amber warning alert for broken credentials with disabled test/edit/discover - Added i18n translation keys for decryption error warning in all 9 locales
This commit is contained in:
parent
4ae459ca5e
commit
ba01f7df4e
15 changed files with 120 additions and 18 deletions
|
|
@ -223,6 +223,7 @@ def credential_to_response(cred: Credential, model_count: int = 0) -> Credential
|
|||
created=str(cred.created) if cred.created else "",
|
||||
updated=str(cred.updated) if cred.updated else "",
|
||||
model_count=model_count,
|
||||
decryption_error=cred.decryption_error,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -617,6 +617,7 @@ class CredentialResponse(BaseModel):
|
|||
created: str
|
||||
updated: str
|
||||
model_count: int = 0
|
||||
decryption_error: Optional[str] = None
|
||||
|
||||
|
||||
class CredentialDeleteResponse(BaseModel):
|
||||
|
|
|
|||
|
|
@ -27,16 +27,22 @@ from pydantic import SecretStr
|
|||
from api.credentials_service import (
|
||||
credential_to_response,
|
||||
discover_with_config,
|
||||
migrate_from_env as svc_migrate_from_env,
|
||||
migrate_from_provider_config as svc_migrate_from_provider_config,
|
||||
get_provider_status,
|
||||
register_models,
|
||||
require_encryption_key,
|
||||
test_credential as svc_test_credential,
|
||||
validate_url,
|
||||
)
|
||||
from api.credentials_service import (
|
||||
get_env_status as svc_get_env_status,
|
||||
get_provider_status,
|
||||
)
|
||||
from api.credentials_service import (
|
||||
migrate_from_env as svc_migrate_from_env,
|
||||
)
|
||||
from api.credentials_service import (
|
||||
migrate_from_provider_config as svc_migrate_from_provider_config,
|
||||
)
|
||||
from api.credentials_service import (
|
||||
test_credential as svc_test_credential,
|
||||
)
|
||||
from api.models import (
|
||||
CreateCredentialRequest,
|
||||
|
|
@ -48,6 +54,7 @@ from api.models import (
|
|||
RegisterModelsResponse,
|
||||
UpdateCredentialRequest,
|
||||
)
|
||||
from open_notebook.database.repository import ensure_record_id, repo_delete, repo_query
|
||||
from open_notebook.domain.credential import Credential
|
||||
|
||||
router = APIRouter(prefix="/credentials", tags=["credentials"])
|
||||
|
|
@ -260,7 +267,36 @@ async def delete_credential(
|
|||
- Otherwise, linked models are cascade-deleted automatically
|
||||
"""
|
||||
try:
|
||||
cred = await Credential.get(credential_id)
|
||||
try:
|
||||
cred = await Credential.get(credential_id)
|
||||
except Exception as decrypt_err:
|
||||
# Credential exists but can't be decrypted (wrong encryption key).
|
||||
# Fall back to direct DB operations for deletion.
|
||||
logger.warning(
|
||||
f"Cannot decrypt credential {credential_id}, "
|
||||
f"falling back to direct delete: {decrypt_err}"
|
||||
)
|
||||
|
||||
# Delete linked models directly
|
||||
linked = await repo_query(
|
||||
"SELECT * FROM model WHERE credential = $cred_id",
|
||||
{"cred_id": ensure_record_id(credential_id)},
|
||||
)
|
||||
deleted_models = 0
|
||||
for model_row in linked:
|
||||
model_id = str(model_row.get("id", ""))
|
||||
if model_id:
|
||||
await repo_delete(model_id)
|
||||
deleted_models += 1
|
||||
|
||||
# Delete the credential itself
|
||||
await repo_delete(credential_id)
|
||||
|
||||
return CredentialDeleteResponse(
|
||||
message="Credential deleted successfully",
|
||||
deleted_models=deleted_models,
|
||||
)
|
||||
|
||||
linked_models = await cred.get_linked_models()
|
||||
|
||||
deleted_models = 0
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue