Initial curated RAGcore source from c16667f0c9397e2bfc8dd0255b114fba23c8d05e
This commit is contained in:
commit
7ca726caf2
659 files changed
+98171
No files matched your search
@@ -0,0 +1,144 @@
|
||||
"""Proves a bearer-authenticated service account can actually resolve real
|
||||
effective spaces end to end against real Postgres.
|
||||
|
||||
Before this fix, `ControlPlaneAuthorizationInputsProvider.load()` always
|
||||
returned `application=None` and `grants=()` for every principal, and
|
||||
`Principal` had no way to even carry which `Application` a service
|
||||
account's bearer credential belongs to. `EffectiveSpaceResolver` only
|
||||
ever honors workspace-level `Grant`s alongside a real `Application`, so
|
||||
every bearer-token search/context/answers call was silently resolving to
|
||||
zero effective spaces, regardless of what it requested -- a real,
|
||||
previously-undetected bug found while building M7-03 (MCP), which relies
|
||||
entirely on this same bearer-token path actually working.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
from sqlalchemy import text
|
||||
|
||||
from ragcore.application.control.spaces import EffectiveSpaceResolver
|
||||
from ragcore.application.identity.credentials import ServiceAccountCredentialService
|
||||
from ragcore.config import Settings
|
||||
from ragcore.domain.authorization import Principal, PrincipalType
|
||||
from ragcore.domain.control import (
|
||||
DataPolicy,
|
||||
Role,
|
||||
Scope,
|
||||
ServiceAccount,
|
||||
SpaceOperation,
|
||||
Workspace,
|
||||
)
|
||||
from ragcore.infrastructure.database import (
|
||||
create_database_engine,
|
||||
create_session_factory,
|
||||
session_scope,
|
||||
)
|
||||
from ragcore.infrastructure.database.control import ControlPlaneRepository
|
||||
from ragcore.infrastructure.database.identity import PostgresCredentialRepository
|
||||
from ragcore.web.query_lab.dependencies import ControlPlaneAuthorizationInputsProvider
|
||||
|
||||
|
||||
@pytest_asyncio.fixture
|
||||
async def session_factory():
|
||||
engine = create_database_engine(Settings(env="test"))
|
||||
factory = create_session_factory(engine)
|
||||
async with session_scope(factory) as session:
|
||||
# See tests/integration/control/test_control_plane.py's own repository
|
||||
# fixture for why control.workspaces is deliberately not truncated.
|
||||
await session.execute(
|
||||
text(
|
||||
"TRUNCATE control.grants, control.policies, control.applications, "
|
||||
"control.spaces, identity.service_account_credentials CASCADE"
|
||||
)
|
||||
)
|
||||
await session.commit()
|
||||
yield factory
|
||||
await engine.dispose()
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_bearer_service_account_resolves_real_granted_space(session_factory) -> None:
|
||||
workspace_id = uuid4()
|
||||
workspace = Workspace(workspace_id, "MCP workspace", f"mcp-workspace-{workspace_id.hex[:8]}")
|
||||
space = workspace.create_knowledge_space(
|
||||
id=uuid4(), name="MCP space", slug="mcp-space", data_policy=DataPolicy.LOCAL_ONLY
|
||||
)
|
||||
application = workspace.create_application(
|
||||
id=uuid4(), name="MCP server", slug="mcp-server", scopes={Scope.SEARCH}
|
||||
)
|
||||
service_account = ServiceAccount(
|
||||
id=uuid4(),
|
||||
workspace_id=workspace.id,
|
||||
application_id=application.id,
|
||||
name="MCP service account",
|
||||
scopes=frozenset({Scope.SEARCH}),
|
||||
)
|
||||
|
||||
async with session_scope(session_factory) as session:
|
||||
repository = ControlPlaneRepository(session)
|
||||
await repository.create_workspace(workspace)
|
||||
await repository.create_space(space)
|
||||
await repository.create_application(application)
|
||||
await repository.create_service_account(service_account)
|
||||
grant = workspace.grant(
|
||||
id=uuid4(), application=application, knowledge_space=space, role=Role.VIEWER
|
||||
)
|
||||
await repository.create_grant(grant)
|
||||
await session.commit()
|
||||
|
||||
async def load_service_account(account_id):
|
||||
async with session_scope(session_factory) as session:
|
||||
return await ControlPlaneRepository(session).get_service_account_by_id(account_id)
|
||||
|
||||
async with session_scope(session_factory) as session:
|
||||
credential_service = ServiceAccountCredentialService(
|
||||
PostgresCredentialRepository(session),
|
||||
"test-credential-pepper-that-is-long-enough",
|
||||
service_account_loader=load_service_account,
|
||||
)
|
||||
issued = await credential_service.issue(service_account, scopes={Scope.SEARCH})
|
||||
await session.commit()
|
||||
|
||||
async with session_scope(session_factory) as session:
|
||||
credential_service = ServiceAccountCredentialService(
|
||||
PostgresCredentialRepository(session),
|
||||
"test-credential-pepper-that-is-long-enough",
|
||||
service_account_loader=load_service_account,
|
||||
)
|
||||
authenticated = await credential_service.authenticate(
|
||||
issued.token, required_scopes=[Scope.SEARCH]
|
||||
)
|
||||
|
||||
assert authenticated is not None
|
||||
assert authenticated.application_id == application.id
|
||||
|
||||
principal = Principal(
|
||||
id=service_account.id,
|
||||
workspace_id=workspace.id,
|
||||
principal_type=PrincipalType.SERVICE_ACCOUNT,
|
||||
roles=frozenset({Role.EDITOR}),
|
||||
application_id=authenticated.application_id,
|
||||
)
|
||||
|
||||
provider = ControlPlaneAuthorizationInputsProvider(session_factory)
|
||||
inputs = await provider.load(principal)
|
||||
|
||||
assert inputs.application is not None
|
||||
assert inputs.application.id == application.id
|
||||
assert any(g.knowledge_space_id == space.id for g in inputs.grants)
|
||||
|
||||
effective_space_ids = EffectiveSpaceResolver().resolve(
|
||||
workspace_id=workspace.id,
|
||||
spaces=inputs.spaces,
|
||||
grants=inputs.grants,
|
||||
user_grants=inputs.user_grants,
|
||||
application=inputs.application,
|
||||
requested_space_ids=(space.id,),
|
||||
operation=SpaceOperation.SEARCH,
|
||||
)
|
||||
|
||||
assert effective_space_ids == frozenset({space.id})
|
||||
Reference in new issue
Block a user