This commit is contained in:
2026-05-20 23:54:53 +03:00
parent a43886106e
commit 68740cd9ed
167 changed files with 10620 additions and 29041 deletions

View File

@@ -11,18 +11,17 @@
# @DATA_CONTRACT Input -> OAuth2PasswordRequestForm -> Token, User
# @INVARIANT All auth endpoints must return consistent error codes.
import starlette.requests
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
import starlette.requests
from ..core.auth.logger import log_security_event
from ..core.auth.oauth import is_adfs_configured, oauth
from ..core.database import get_auth_db
from ..core.logger import belief_scope
from ..dependencies import get_current_user
from ..schemas.auth import Token
from ..schemas.auth import User as UserSchema
from ..schemas.auth import Token, User as UserSchema
from ..services.auth_service import AuthService
# #region router [C:1] [TYPE Variable]

View File

@@ -6,9 +6,9 @@ os.environ["ENCRYPTION_KEY"] = "OnrCzomBWbIjTf7Y-fnhL2adlU55bHZQjp8zX5zBC5w="
# @RELATION DEPENDS_ON -> [AssistantApi]
# @INVARIANT: Every test clears assistant in-memory state before execution.
import asyncio
import uuid
from datetime import datetime
from unittest.mock import MagicMock
import uuid
from src.api.routes import assistant as assistant_routes
from src.models.assistant import AssistantMessageRecord

View File

@@ -7,11 +7,11 @@ os.environ["ENCRYPTION_KEY"] = "OnrCzomBWbIjTf7Y-fnhL2adlU55bHZQjp8zX5zBC5w="
# @RELATION DEPENDS_ON -> AssistantApi
# @INVARIANT: Security-sensitive flows fail closed for unauthorized actors.
import asyncio
import os
from datetime import datetime, timedelta
import os
import pytest
from types import SimpleNamespace
import pytest
from fastapi import HTTPException
# Force isolated sqlite databases for test module before dependencies import.

View File

@@ -4,8 +4,8 @@
# @LAYER: Tests
from __future__ import annotations
import os
from datetime import UTC, datetime
import os
from fastapi.testclient import TestClient

View File

@@ -4,10 +4,10 @@
# @RELATION DEPENDS_ON -> ConnectionsRouter
import asyncio
import os
import sys
from pathlib import Path
import pytest
import sys
from sqlalchemy import create_engine, inspect
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool

View File

@@ -3,9 +3,9 @@
# @LAYER: API
# @RELATION DEPENDS_ON -> [DashboardsApi]
from datetime import UTC, datetime
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from fastapi.testclient import TestClient
from src.api.routes.dashboards import DashboardsResponse

View File

@@ -4,10 +4,10 @@
# @RELATION [BINDS_TO] ->[DatasetReviewApi]
# @RELATION [BINDS_TO] ->[DatasetReviewOrchestrator]
from datetime import UTC, datetime
import pytest
from types import SimpleNamespace
from unittest.mock import MagicMock, patch
import pytest
from fastapi.testclient import TestClient
from src.api.routes.dataset_review import (

View File

@@ -3,9 +3,9 @@
# @LAYER: API
# @RELATION DEPENDS_ON -> [DatasetsApi]
# @INVARIANT: Endpoint contracts remain stable for success and validation failure paths.
import pytest
from unittest.mock import AsyncMock, MagicMock
import pytest
from fastapi.testclient import TestClient
from src.api.routes.datasets import DatasetsResponse

View File

@@ -2,9 +2,9 @@
# @RELATION VERIFIES -> [GitApi]
# @BRIEF API tests for Git configurations and repository operations.
import asyncio
import pytest
from unittest.mock import MagicMock
import pytest
from fastapi import HTTPException
from src.api.routes import git as git_routes

View File

@@ -3,9 +3,9 @@
# @LAYER: Domain
# @RELATION VERIFIES -> [GitApi]
import asyncio
import pytest
from unittest.mock import MagicMock
import pytest
from fastapi import HTTPException
from src.api.routes import git as git_routes

View File

@@ -4,12 +4,11 @@
# @LAYER: API
# @RELATION VERIFIES -> backend.src.api.routes.migration
#
import sys
from datetime import UTC, datetime
from pathlib import Path
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
import sys
from unittest.mock import AsyncMock, MagicMock, patch
# Add backend directory to sys.path
backend_dir = str(Path(__file__).parent.parent.parent.parent.resolve())

View File

@@ -2,9 +2,9 @@
# @RELATION VERIFIES -> [src.api.routes.tasks:Module]
# @BRIEF Contract testing for task logs API endpoints.
# @LAYER: Domain
import pytest
from unittest.mock import MagicMock
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient

View File

@@ -25,12 +25,10 @@ from ...schemas.auth import (
RoleCreate,
RoleSchema,
RoleUpdate,
User as UserSchema,
UserCreate,
UserUpdate,
)
from ...schemas.auth import (
User as UserSchema,
)
from ...services.rbac_permission_catalog import (
discover_declared_permissions,
sync_permission_catalog,

View File

@@ -6,9 +6,9 @@
from __future__ import annotations
import uuid
from datetime import datetime, timedelta
from typing import Any
import uuid
from sqlalchemy.orm import Session

View File

@@ -101,7 +101,7 @@ def _resolve_provider_id(
if bound_provider_id and any(p.id == bound_provider_id for p in providers):
return bound_provider_id
except Exception:
pass
logger.debug("Could not resolve bound provider for task_key=%s", task_key)
active = next((p for p in providers if p.is_active), None)
return active.id if active else providers[0].id

View File

@@ -12,8 +12,8 @@
from __future__ import annotations
import uuid
from datetime import datetime
import uuid
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session

View File

@@ -1,9 +1,10 @@
# #region AssistantSchemas [C:2] [TYPE Module] [SEMANTICS assistant, pydantic, schema, store, permission]
# @BRIEF Pydantic models, in-memory stores, and permission mappings for the assistant API.
# @LAYER: API
# @RELATION USED_BY -> [AssistantRoutes]
# @LAYER API
# @RELATION USED_BY -> [AssistantHistory]
# @INVARIANT: In-memory stores are module-level singletons shared across the assistant package.
# @RELATION USED_BY -> [AssistantHistory]
# @INVARIANT In-memory stores are module-level singletons shared across the assistant package.
# @RATIONALE In-memory stores documented with NOTE about restart loss. ASSISTANT_ARCHIVE_AFTER_DAYS and ASSISTANT_MESSAGE_TTL_DAYS kept as module-level constants with TODO for config migration — Pydantic schemas module should not depend on ConfigManager for architectural purity.
from __future__ import annotations
@@ -15,12 +16,12 @@ from pydantic import BaseModel, Field
# #region AssistantMessageRequest [C:1] [TYPE Class]
# @BRIEF Input payload for assistant message endpoint.
# @DATA_CONTRACT: Input[conversation_id?:str, message:str(1..4000)] -> Output[AssistantMessageRequest]
# @DATA_CONTRACT Input[conversation_id?:str, message:str(1..4000)] -> Output[AssistantMessageRequest]
# @RELATION USED_BY -> [send_message]
# @SIDE_EFFECT: None (schema declaration only).
# @PRE: message length is within accepted bounds.
# @POST: Request object provides message text and optional conversation binding.
# @INVARIANT: message is always non-empty and no longer than 4000 characters.
# @SIDE_EFFECT None (schema declaration only).
# @PRE message length is within accepted bounds.
# @POST Request object provides message text and optional conversation binding.
# @INVARIANT message is always non-empty and no longer than 4000 characters.
class AssistantMessageRequest(BaseModel):
conversation_id: str | None = None
message: str = Field(..., min_length=1, max_length=4000)
@@ -32,12 +33,12 @@ class AssistantMessageRequest(BaseModel):
# #region AssistantAction [C:1] [TYPE Class]
# @BRIEF UI action descriptor returned with assistant responses.
# @DATA_CONTRACT: Input[type:str, label:str, target?:str] -> Output[AssistantAction]
# @DATA_CONTRACT Input[type:str, label:str, target?:str] -> Output[AssistantAction]
# @RELATION USED_BY -> [AssistantMessageResponse]
# @SIDE_EFFECT: None (schema declaration only).
# @PRE: type and label are provided by orchestration logic.
# @POST: Action can be rendered as button on frontend.
# @INVARIANT: type and label are required for every UI action.
# @SIDE_EFFECT None (schema declaration only).
# @PRE type and label are provided by orchestration logic.
# @POST Action can be rendered as button on frontend.
# @INVARIANT type and label are required for every UI action.
class AssistantAction(BaseModel):
type: str
label: str
@@ -49,14 +50,14 @@ class AssistantAction(BaseModel):
# #region AssistantMessageResponse [C:1] [TYPE Class]
# @BRIEF Output payload contract for assistant interaction endpoints.
# @DATA_CONTRACT: Input[conversation_id,response_id,state,text,intent?,confirmation_id?,task_id?,actions[],created_at] -> Output[AssistantMessageResponse]
# @DATA_CONTRACT Input[conversation_id,response_id,state,text,intent?,confirmation_id?,task_id?,actions[],created_at] -> Output[AssistantMessageResponse]
# @RELATION RETURNED_BY -> [send_message]
# @RELATION RETURNED_BY -> [confirm_operation]
# @RELATION RETURNED_BY -> [cancel_operation]
# @SIDE_EFFECT: None (schema declaration only).
# @PRE: Response includes deterministic state and text.
# @POST: Payload may include task_id/confirmation_id/actions for UI follow-up.
# @INVARIANT: created_at and state are always present in endpoint responses.
# @SIDE_EFFECT None (schema declaration only).
# @PRE Response includes deterministic state and text.
# @POST Payload may include task_id/confirmation_id/actions for UI follow-up.
# @INVARIANT created_at and state are always present in endpoint responses.
class AssistantMessageResponse(BaseModel):
conversation_id: str
response_id: str
@@ -74,14 +75,14 @@ class AssistantMessageResponse(BaseModel):
# #region ConfirmationRecord [C:1] [TYPE Class]
# @BRIEF In-memory confirmation token model for risky operation dispatch.
# @DATA_CONTRACT: Input[id,user_id,conversation_id,intent,dispatch,expires_at,state?,created_at] -> Output[ConfirmationRecord]
# @DATA_CONTRACT Input[id,user_id,conversation_id,intent,dispatch,expires_at,state?,created_at] -> Output[ConfirmationRecord]
# @RELATION USED_BY -> [send_message]
# @RELATION USED_BY -> [confirm_operation]
# @RELATION USED_BY -> [cancel_operation]
# @SIDE_EFFECT: None (schema declaration only).
# @PRE: intent/dispatch/user_id are populated at confirmation request time.
# @POST: Record tracks lifecycle state and expiry timestamp.
# @INVARIANT: state defaults to "pending" and expires_at bounds confirmation validity.
# @SIDE_EFFECT None (schema declaration only).
# @PRE intent/dispatch/user_id are populated at confirmation request time.
# @POST Record tracks lifecycle state and expiry timestamp.
# @INVARIANT state defaults to "pending" and expires_at bounds confirmation validity.
class ConfirmationRecord(BaseModel):
id: str
user_id: str

View File

@@ -6,7 +6,7 @@
import sys
# Batch limit for repository status queries
# Guard value: batch limit for repository status queries prevents overload on large repo sets
MAX_REPOSITORY_STATUS_BATCH: int = 50

View File

@@ -251,7 +251,7 @@ def _resolve_repo_key_from_ref(
if dashboard_slug:
return str(dashboard_slug)
except Exception:
pass
logger.debug("Could not resolve dashboard slug for dashboard_id=%s", dashboard_id)
return f"dashboard-{dashboard_id}"
# #endregion _resolve_repo_key_from_ref

View File

@@ -35,7 +35,6 @@ class FetchModelsRequest(BaseModel):
router = APIRouter(tags=["LLM"])
# #endregion router
# #endregion router
# #region _is_valid_runtime_api_key [C:4] [TYPE Function]

View File

@@ -12,13 +12,11 @@ from ....core.logger import belief_scope, logger
from ....dependencies import get_config_manager, get_current_user, has_permission
from ....plugins.translate.service import (
TranslateJobService,
get_datasource_columns as fetch_datasource_columns_service,
job_to_response,
)
from ....plugins.translate.service import (
get_datasource_columns as fetch_datasource_columns_service,
)
from ....schemas.auth import User
from ....plugins.translate.service_target_schema import validate_target_table_schema
from ....schemas.auth import User
from ....schemas.translate import (
DatasourceColumnsResponse,
DuplicateJobResponse,

View File

@@ -57,14 +57,14 @@ async def list_runs(
dt_from = datetime.fromisoformat(date_from)
query = query.filter(TranslationRun.created_at >= dt_from)
except ValueError:
pass
logger.debug("Could not parse date_from: %s", date_from)
if date_to:
try:
from datetime import datetime
dt_to = datetime.fromisoformat(date_to)
query = query.filter(TranslationRun.created_at <= dt_to)
except ValueError:
pass
logger.debug("Could not parse date_to: %s", date_to)
total = query.count()
runs = (