Initial curated RAGcore source from c16667f0c9397e2bfc8dd0255b114fba23c8d05e

This commit is contained in:
Public Source Publisher committed 2026-10-01 01:34:21 +02:00
commit 7ca726caf2
659 files changed
+98171

No files matched your search

@@ -0,0 +1,150 @@
"""Adversarial tests for the shared Bearer-token principal fallback."""
from __future__ import annotations
from uuid import UUID, uuid4
import pytest
from fastapi import Request
from ragcore.api.v1.control.bearer_auth import bearer_principal
from ragcore.api.v1.control.dependencies import ControlAPIProblem
from ragcore.application.identity.credentials import ServiceAccountCredentialService
from ragcore.domain.authorization import Principal, PrincipalType
from ragcore.domain.control import Role, Scope, ServiceAccount, Workspace
from ragcore.infrastructure.database.identity import InMemoryCredentialRepository
PEPPER = "test-credential-pepper-that-is-long-enough"
def _token_factory(credential_id: UUID) -> str:
return f"rc_sa_{credential_id.hex}_{'a' * 43}"
def _request(headers: dict[bytes, bytes]) -> Request:
return Request({"type": "http", "headers": list(headers.items())})
def _service_account(scopes: set[Scope]) -> tuple[Workspace, ServiceAccount]:
frozen_scopes = frozenset(scopes)
workspace = Workspace(uuid4(), "Test", "test")
application = workspace.create_application(
id=uuid4(), name="n8n", slug="n8n", scopes=frozen_scopes
)
account = ServiceAccount(
id=uuid4(),
workspace_id=workspace.id,
application_id=application.id,
name="n8n worker",
scopes=frozen_scopes,
active=True,
)
return workspace, account
async def _credential_service(
account: ServiceAccount | None,
) -> ServiceAccountCredentialService:
async def load(account_id: UUID) -> ServiceAccount | None:
return account if account is not None and account_id == account.id else None
return ServiceAccountCredentialService(
InMemoryCredentialRepository(),
PEPPER,
service_account_loader=load,
token_factory=_token_factory,
)
@pytest.mark.security
async def test_bearer_principal_accepts_a_correctly_scoped_token() -> None:
workspace, account = _service_account({Scope.SEARCH})
credential_service = await _credential_service(account)
issued = await credential_service.issue(account, scopes={Scope.SEARCH})
dependency = bearer_principal(Scope.SEARCH)
request = _request({b"authorization": f"Bearer {issued.token}".encode()})
result = await dependency(request, credential_service)
assert result.principal_type is PrincipalType.SERVICE_ACCOUNT
assert result.id == account.id
assert result.workspace_id == workspace.id
assert Role.EDITOR in result.roles
@pytest.mark.security
async def test_bearer_principal_prefers_an_existing_session_principal() -> None:
workspace, account = _service_account({Scope.CONTEXT})
credential_service = await _credential_service(account)
issued = await credential_service.issue(account, scopes={Scope.CONTEXT})
session_principal = Principal(
id=uuid4(), workspace_id=workspace.id, principal_type=PrincipalType.HUMAN
)
request = _request({b"authorization": f"Bearer {issued.token}".encode()})
request.state.principal = session_principal
result = await bearer_principal(Scope.CONTEXT)(request, credential_service)
assert result is session_principal
@pytest.mark.security
async def test_bearer_principal_rejects_wrong_scope_missing_header_and_malformed_token() -> None:
_workspace, account = _service_account({Scope.SEARCH})
credential_service = await _credential_service(account)
issued = await credential_service.issue(account, scopes={Scope.SEARCH})
dependency = bearer_principal(Scope.ANSWER)
scoped_request = _request({b"authorization": f"Bearer {issued.token}".encode()})
with pytest.raises(ControlAPIProblem) as wrong_scope:
await dependency(scoped_request, credential_service)
assert wrong_scope.value.status == 401
with pytest.raises(ControlAPIProblem) as no_header:
await dependency(_request({}), credential_service)
assert no_header.value.status == 401
with pytest.raises(ControlAPIProblem) as malformed:
await dependency(
_request({b"authorization": b"Bearer not-a-real-token"}), credential_service
)
assert malformed.value.status == 401
@pytest.mark.security
async def test_bearer_principal_rejects_deactivated_service_account() -> None:
_workspace, account = _service_account({Scope.ANSWER})
repository = InMemoryCredentialRepository()
async def load_active(account_id: UUID) -> ServiceAccount | None:
return account if account_id == account.id else None
issuing_service = ServiceAccountCredentialService(
repository, PEPPER, service_account_loader=load_active, token_factory=_token_factory
)
issued = await issuing_service.issue(account, scopes={Scope.ANSWER})
inactive_account = ServiceAccount(
id=account.id,
workspace_id=account.workspace_id,
application_id=account.application_id,
name=account.name,
scopes=account.scopes,
active=False,
)
async def load_inactive(account_id: UUID) -> ServiceAccount | None:
return inactive_account if account_id == account.id else None
authenticating_service = ServiceAccountCredentialService(
repository, PEPPER, service_account_loader=load_inactive, token_factory=_token_factory
)
with pytest.raises(ControlAPIProblem) as error:
await bearer_principal(Scope.ANSWER)(
_request({b"authorization": f"Bearer {issued.token}".encode()}),
authenticating_service,
)
assert error.value.status == 401
+241
View File
@@ -0,0 +1,241 @@
"""Adversarial tests for service-account bearer credential lifecycle."""
from __future__ import annotations
import asyncio
from datetime import UTC, datetime, timedelta
from uuid import UUID, uuid4
import pytest
from ragcore.application.identity import ServiceAccountCredentialService
from ragcore.domain.control import Scope, ServiceAccount, Workspace
from ragcore.domain.identity import CredentialLimitExceeded, CredentialScopeViolation
from ragcore.infrastructure.database.identity import InMemoryCredentialRepository
NOW = datetime(2026, 1, 1, tzinfo=UTC)
PEPPER = "test-credential-pepper-that-is-long-enough"
def service_account(*, active: bool = True) -> ServiceAccount:
workspace = Workspace(uuid4(), "Test", "test")
application = workspace.create_application(
id=uuid4(), name="Client", slug="client", scopes={Scope.SEARCH, Scope.CONTEXT}
)
return ServiceAccount(
id=uuid4(),
workspace_id=workspace.id,
application_id=application.id,
name="Worker",
scopes={Scope.SEARCH, Scope.CONTEXT},
active=active,
)
def token_factory(credential_id: UUID) -> str:
return f"rc_sa_{credential_id.hex}_{'a' * 43}"
def build_service(
repository: InMemoryCredentialRepository, accounts: tuple[ServiceAccount, ...]
) -> tuple[ServiceAccountCredentialService, dict[UUID, ServiceAccount]]:
state = {account.id: account for account in accounts}
async def load(account_id: UUID) -> ServiceAccount | None:
return state.get(account_id)
return (
ServiceAccountCredentialService(
repository,
PEPPER,
service_account_loader=load,
clock=lambda: NOW,
token_factory=token_factory,
),
state,
)
@pytest.mark.security
async def test_plaintext_is_returned_once_and_never_stored() -> None:
repository = InMemoryCredentialRepository()
account = service_account()
service, _ = build_service(repository, (account,))
issued = await service.issue(account, scopes={Scope.SEARCH})
assert issued.token.startswith("rc_sa_")
record = await repository.get(issued.credential.id, account.id, account.workspace_id)
assert record is not None
assert issued.token not in repr(record)
assert issued.token.encode() != record.token_digest
assert issued.token not in repr(repository.snapshot())
@pytest.mark.security
async def test_wrong_scope_wrong_token_expired_and_revoked_fail_closed() -> None:
repository = InMemoryCredentialRepository()
account = service_account()
service, _ = build_service(repository, (account,))
issued = await service.issue(
account, scopes={Scope.SEARCH}, expires_at=NOW + timedelta(hours=1)
)
assert await service.verify(
issued.token, service_account=account, required_scopes={Scope.SEARCH}
)
assert (
await service.verify(issued.token, service_account=account, required_scopes={Scope.CONTEXT})
is None
)
assert await service.verify(issued.token[:-1] + "b", service_account=account) is None
assert (
await service.verify(issued.token, service_account=account, now=NOW + timedelta(hours=1))
is None
)
assert await service.revoke(issued.credential.id, account)
assert await service.verify(issued.token, service_account=account) is None
@pytest.mark.security
async def test_authoritative_deactivation_and_scope_reduction_fail_closed() -> None:
repository = InMemoryCredentialRepository()
account = service_account()
service, state = build_service(repository, (account,))
issued = await service.issue(account, scopes={Scope.SEARCH, Scope.CONTEXT})
state[account.id] = ServiceAccount(
id=account.id,
workspace_id=account.workspace_id,
application_id=account.application_id,
name=account.name,
scopes={Scope.SEARCH},
active=True,
)
assert (
await service.verify(issued.token, service_account=account, required_scopes={Scope.CONTEXT})
is None
)
state[account.id] = ServiceAccount(
id=account.id,
workspace_id=account.workspace_id,
application_id=account.application_id,
name=account.name,
scopes={Scope.SEARCH},
active=False,
)
assert await service.verify(issued.token, service_account=account) is None
@pytest.mark.security
async def test_inactive_service_accounts_fail_closed() -> None:
repository = InMemoryCredentialRepository()
account = service_account()
service, state = build_service(repository, (account,))
inactive_account = ServiceAccount(
id=account.id,
workspace_id=account.workspace_id,
application_id=account.application_id,
name=account.name,
scopes=account.scopes,
active=False,
)
state[account.id] = inactive_account
with pytest.raises(ValueError, match="authoritative"):
await service.issue(inactive_account, scopes={Scope.SEARCH})
@pytest.mark.security
async def test_scope_escalation_is_rejected() -> None:
repository = InMemoryCredentialRepository()
account = service_account()
service, _ = build_service(repository, (account,))
with pytest.raises(CredentialScopeViolation):
await service.issue(account, scopes={Scope.ANSWER})
@pytest.mark.security
async def test_rotation_keeps_at_most_two_active_credentials_with_overlap() -> None:
repository = InMemoryCredentialRepository()
account = service_account()
service, _ = build_service(repository, (account,))
first = await service.issue(account, scopes={Scope.SEARCH})
second = await service.issue(account, scopes={Scope.SEARCH})
with pytest.raises(CredentialLimitExceeded):
await service.issue(account, scopes={Scope.SEARCH})
third = await service.issue(account, scopes={Scope.SEARCH}, rotate=True)
assert await service.verify(first.token, service_account=account) is None
assert await service.verify(second.token, service_account=account)
assert await service.verify(third.token, service_account=account)
assert len(await repository.list_active(account.id, account.workspace_id, NOW)) == 2
@pytest.mark.security
async def test_authenticate_accepts_valid_token_without_a_caller_supplied_account() -> None:
repository = InMemoryCredentialRepository()
account = service_account()
service, _ = build_service(repository, (account,))
issued = await service.issue(account, scopes={Scope.SEARCH})
authenticated = await service.authenticate(issued.token, required_scopes={Scope.SEARCH})
assert authenticated is not None
assert authenticated.service_account_id == account.id
assert authenticated.workspace_id == account.workspace_id
@pytest.mark.security
async def test_authenticate_rejects_malformed_unknown_wrong_scope_expired_and_revoked() -> None:
repository = InMemoryCredentialRepository()
account = service_account()
service, _ = build_service(repository, (account,))
issued = await service.issue(
account, scopes={Scope.SEARCH}, expires_at=NOW + timedelta(hours=1)
)
assert await service.authenticate("not-a-real-token") is None
assert await service.authenticate(f"rc_sa_{uuid4().hex}_{'a' * 43}") is None
assert await service.authenticate(issued.token[:-1] + "b") is None
assert await service.authenticate(issued.token, required_scopes={Scope.CONTEXT}) is None
assert (
await service.authenticate(issued.token, now=NOW + timedelta(hours=1)) is None
)
assert await service.revoke(issued.credential.id, account)
assert await service.authenticate(issued.token) is None
@pytest.mark.security
async def test_authenticate_rejects_deactivated_service_account() -> None:
repository = InMemoryCredentialRepository()
account = service_account()
service, state = build_service(repository, (account,))
issued = await service.issue(account, scopes={Scope.SEARCH})
state[account.id] = ServiceAccount(
id=account.id,
workspace_id=account.workspace_id,
application_id=account.application_id,
name=account.name,
scopes=account.scopes,
active=False,
)
assert await service.authenticate(issued.token) is None
@pytest.mark.security
async def test_concurrent_issuance_stays_within_rotation_limit() -> None:
repository = InMemoryCredentialRepository()
account = service_account()
service, _ = build_service(repository, (account,))
results = await asyncio.gather(
*(service.issue(account, scopes={Scope.SEARCH}) for _ in range(3)),
return_exceptions=True,
)
assert sum(not isinstance(result, CredentialLimitExceeded) for result in results) == 2
assert len(await repository.list_active(account.id, account.workspace_id, NOW)) == 2