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

+539
View File
@@ -0,0 +1,539 @@
from __future__ import annotations
import asyncio
import hashlib
from collections.abc import AsyncIterable
from uuid import uuid4
from fastapi.testclient import TestClient
from ragcore.api.v1.control.dependencies import (
get_control_application,
get_credential_service,
get_principal,
)
from ragcore.api.v1.uploads.dependencies import get_upload_service
from ragcore.application.authorization import AuthorizationService
from ragcore.application.control.api import ControlPlaneApplication
from ragcore.application.documents import DocumentRecord
from ragcore.application.identity.credentials import ServiceAccountCredentialService
from ragcore.application.jobs import Job, JobService
from ragcore.application.storage import BlobReference
from ragcore.domain.authorization import Principal, PrincipalType
from ragcore.domain.control import (
Application,
Grant,
KnowledgeSpace,
Policy,
Role,
Scope,
ServiceAccount,
UserGrant,
Workspace,
)
from ragcore.infrastructure.connectors.upload import (
UploadIdempotencyStore,
UploadPolicy,
UploadService,
)
from ragcore.infrastructure.database.identity.memory import InMemoryCredentialRepository
from ragcore.main import create_app
class RecordingBlobStorage:
def __init__(self) -> None:
self.calls = 0
async def put(
self,
chunks: AsyncIterable[bytes],
*,
media_type: str | None = None,
original_name: str | None = None,
expected_sha256: str | None = None,
) -> BlobReference:
self.calls += 1
body = b"".join([chunk async for chunk in chunks])
digest = hashlib.sha256(body).hexdigest()
return BlobReference(
digest=digest,
size=len(body),
media_type=media_type,
original_name=original_name,
storage_key=f"blobs/{digest}",
)
class RecordingJobRepository:
def __init__(self) -> None:
self.calls = 0
self.enqueued: list[Job] = []
async def enqueue(self, job: Job) -> Job:
self.calls += 1
self.enqueued.append(job)
return job
class FakeControlRepository:
def __init__(self, workspace: Workspace) -> None:
self.workspace = workspace
self.applications: list[Application] = []
self.service_accounts: list[ServiceAccount] = []
self.spaces: list[KnowledgeSpace] = []
self.grants: list[Grant | UserGrant] = []
self.policies: list[Policy] = []
async def get_workspace(self, workspace_id):
return self.workspace if workspace_id == self.workspace.id else None
async def create_application(self, entity):
self.applications.append(entity)
return entity
async def get_application(self, application_id, workspace_id):
return next(
(
item
for item in self.applications
if item.id == application_id and item.workspace_id == workspace_id
),
None,
)
async def list_applications(self, workspace_id):
return tuple(item for item in self.applications if item.workspace_id == workspace_id)
async def create_service_account(self, entity):
self.service_accounts.append(entity)
return entity
async def get_service_account_by_id(self, service_account_id):
return next((item for item in self.service_accounts if item.id == service_account_id), None)
async def create_space(self, entity):
self.spaces.append(entity)
return entity
async def list_spaces(self, workspace_id):
return tuple(item for item in self.spaces if item.workspace_id == workspace_id)
async def update_space(self, entity):
self.spaces = [entity if item.id == entity.id else item for item in self.spaces]
return entity
async def create_grant(self, entity):
self.grants.append(entity)
return entity
async def create_user_grant(self, entity):
self.grants.append(entity)
return entity
async def create_policy(self, entity):
self.policies.append(entity)
return entity
async def list_policies(self, workspace_id):
return tuple(item for item in self.policies if item.workspace_id == workspace_id)
async def list_grants(self, workspace_id):
return tuple(
item
for item in self.grants
if isinstance(item, Grant) and item.workspace_id == workspace_id
)
class FakeDocumentRepository:
def __init__(self) -> None:
self.documents: list[DocumentRecord] = []
async def create_document(self, document: DocumentRecord) -> DocumentRecord:
self.documents.append(document)
return document
async def create_version(self, version): # type: ignore[no-untyped-def]
raise AssertionError("should not be reached in these tests")
async def get_version(self, version_id): # type: ignore[no-untyped-def]
raise AssertionError("should not be reached in these tests")
async def publish_validated(self, version_id, artifacts, chunks): # type: ignore[no-untyped-def]
raise AssertionError("should not be reached in these tests")
async def mark_source_deleted(self, document_id): # type: ignore[no-untyped-def]
raise AssertionError("should not be reached in these tests")
async def list_searchable_versions(self, document_id): # type: ignore[no-untyped-def]
raise AssertionError("should not be reached in these tests")
async def list_documents_by_space(self, space_id): # type: ignore[no-untyped-def]
return tuple(item for item in self.documents if item.space_id == space_id)
async def list_documents_by_space_with_status(self, space_id): # type: ignore[no-untyped-def]
from ragcore.application.documents import DocumentStatusRecord, DocumentVersionState
return tuple(
DocumentStatusRecord(
document=item,
latest_state=DocumentVersionState.PUBLISHED,
parser_version="text-parser-1",
chunk_profile_version="prose-v1",
updated_at=None,
)
for item in self.documents
if item.space_id == space_id
)
def _fixture():
workspace = Workspace(uuid4(), "Web workspace", "web-workspace")
principal = Principal(
uuid4(), workspace.id, PrincipalType.HUMAN, frozenset({Role.WORKSPACE_ADMIN})
)
repository = FakeControlRepository(workspace)
document_repository = FakeDocumentRepository()
repository.documents = document_repository
application = workspace.create_application(
id=uuid4(),
name="Web application",
slug="web-application",
scopes=frozenset({Scope.SEARCH}),
)
asyncio.run(repository.create_application(application))
service = ControlPlaneApplication(
repository, AuthorizationService(), document_repository=document_repository
)
credentials = InMemoryCredentialRepository()
credential_service = ServiceAccountCredentialService(
credentials,
"x" * 32,
repository.get_service_account_by_id,
)
blob_storage = RecordingBlobStorage()
job_repository = RecordingJobRepository()
repository.uploads = job_repository
upload_service = UploadService(
blob_storage,
JobService(job_repository),
policy=UploadPolicy(),
idempotency=UploadIdempotencyStore(),
)
app = create_app()
app.dependency_overrides[get_principal] = lambda: principal
app.dependency_overrides[get_control_application] = lambda: service
app.dependency_overrides[get_credential_service] = lambda: credential_service
app.dependency_overrides[get_upload_service] = lambda: upload_service
return app, repository, principal, application
def test_control_screens_have_empty_states_and_accessible_landmarks() -> None:
app, _, _, _ = _fixture()
client = TestClient(app)
for path, heading in (
("/admin/control/applications", "Applications"),
("/admin/control/spaces", "Knowledge spaces"),
("/admin/control/policies", "Policies"),
):
response = client.get(path)
assert response.status_code == 200
assert heading in response.text
if path != "/admin/control/applications":
assert 'role="status"' in response.text
html = client.get("/admin/control/applications").text
assert 'href="#main-content"' in html
assert '<nav aria-label="Primary navigation">' in html
assert 'id="main-content"' in html
assert client.get("/static/admin.css").status_code == 200
assert ":focus-visible" in client.get("/static/admin.css").text
def test_forbidden_control_screen_is_explicit_and_does_not_leak_data() -> None:
app, _, principal, _ = _fixture()
denied = Principal(
principal.id, principal.workspace_id, PrincipalType.HUMAN, frozenset({Role.VIEWER})
)
app.dependency_overrides[get_principal] = lambda: denied
response = TestClient(app).get("/admin/control/applications")
assert response.status_code == 403
assert "Access denied" in response.text
assert "Web application" not in response.text
assert "Reference:" in response.text
def test_credential_plaintext_is_rendered_once() -> None:
app, _, _, application = _fixture()
client = TestClient(app)
form = client.get(f"/admin/control/applications/{application.id}/credentials/new")
assert form.status_code == 200
assert "One-time plaintext token" not in form.text
assert '<nav aria-label="Breadcrumb"' in form.text
assert "Web application" in form.text
issued = client.post(
f"/admin/control/applications/{application.id}/credentials",
data={"name": "browser credential", "scopes": ["search"]},
)
assert issued.status_code == 201
assert "rc_sa_" in issued.text
assert "It will not be shown again" in issued.text
refreshed = client.get(f"/admin/control/applications/{application.id}/credentials/new")
assert refreshed.status_code == 200
assert "rc_sa_" not in refreshed.text
def test_grant_screen_and_error_state_are_authorized() -> None:
app, _, _, _ = _fixture()
client = TestClient(app)
missing = client.get(f"/admin/control/spaces/{uuid4()}/grants")
assert missing.status_code == 404
assert "Knowledge space not found" in missing.text
assert "Reference:" in missing.text
def test_grants_page_lists_real_application_grants_for_the_space() -> None:
app, repository, _, application = _fixture()
space = repository.workspace.create_knowledge_space(
id=uuid4(), name="Runbooks", slug="runbooks"
)
asyncio.run(repository.create_space(space))
grant = repository.workspace.grant(
id=uuid4(), application=application, knowledge_space=space, role=Role.VIEWER
)
asyncio.run(repository.create_grant(grant))
client = TestClient(app)
response = client.get(f"/admin/control/spaces/{space.id}/grants")
assert response.status_code == 200
assert "Web application" in response.text
assert "viewer" in response.text
assert '<nav aria-label="Breadcrumb"' in response.text
assert "Runbooks" in response.text
def test_documents_page_missing_space_is_a_stable_not_found() -> None:
app, _, _, _ = _fixture()
client = TestClient(app)
response = client.get(f"/admin/control/spaces/{uuid4()}/documents")
assert response.status_code == 404
assert "Knowledge space not found" in response.text
def test_documents_page_has_an_empty_state() -> None:
app, repository, _, _ = _fixture()
space = repository.workspace.create_knowledge_space(
id=uuid4(), name="Fleet Ops Procedures", slug="fleet-ops-procedures"
)
asyncio.run(repository.create_space(space))
client = TestClient(app)
response = client.get(f"/admin/control/spaces/{space.id}/documents")
assert response.status_code == 200
assert "No documents yet" in response.text
assert 'role="status"' in response.text
def test_documents_page_lists_ingested_documents_for_the_space() -> None:
app, repository, _, _ = _fixture()
space = repository.workspace.create_knowledge_space(
id=uuid4(), name="Fleet Ops Procedures", slug="fleet-ops-procedures"
)
asyncio.run(repository.create_space(space))
document = DocumentRecord(
id=uuid4(),
workspace_id=repository.workspace.id,
space_id=space.id,
source_key="a" * 64,
external_id="runbook.txt",
title="Fleet restart runbook",
)
asyncio.run(repository.documents.create_document(document))
client = TestClient(app)
response = client.get(f"/admin/control/spaces/{space.id}/documents")
assert response.status_code == 200
assert "Fleet restart runbook" in response.text
assert "runbook.txt" in response.text
assert '<nav aria-label="Breadcrumb"' in response.text
assert "Fleet Ops Procedures" in response.text
def test_new_space_form_renders() -> None:
app, _, _, _ = _fixture()
client = TestClient(app)
response = client.get("/admin/control/spaces/new")
assert response.status_code == 200
assert "Create a knowledge space" in response.text
assert 'action="/admin/control/spaces"' in response.text
def test_create_space_persists_and_redirects_to_the_list() -> None:
app, repository, _, _ = _fixture()
client = TestClient(app)
response = client.post(
"/admin/control/spaces",
data={"name": "Fleet Ops Procedures", "slug": "fleet-ops-procedures"},
follow_redirects=False,
)
assert response.status_code == 303
assert response.headers["location"] == "/admin/control/spaces"
created = asyncio.run(repository.list_spaces(repository.workspace.id))
assert any(space.slug == "fleet-ops-procedures" for space in created)
listing = client.get("/admin/control/spaces")
assert "Fleet Ops Procedures" in listing.text
def test_create_space_rejects_an_invalid_slug_without_persisting() -> None:
app, repository, _, _ = _fixture()
client = TestClient(app)
response = client.post(
"/admin/control/spaces",
data={"name": "Bad Slug", "slug": "Not A Valid Slug!"},
)
assert response.status_code == 400
assert "lowercase letters, numbers and single hyphens" in response.text
assert not asyncio.run(repository.list_spaces(repository.workspace.id))
def test_deactivate_then_activate_space_round_trips() -> None:
app, repository, _, _ = _fixture()
space = repository.workspace.create_knowledge_space(
id=uuid4(), name="Runbooks", slug="runbooks"
)
asyncio.run(repository.create_space(space))
client = TestClient(app)
deactivated = client.post(
f"/admin/control/spaces/{space.id}/deactivate", follow_redirects=False
)
assert deactivated.status_code == 303
stored = asyncio.run(repository.list_spaces(repository.workspace.id))
assert stored[0].active is False
reactivated = client.post(f"/admin/control/spaces/{space.id}/activate", follow_redirects=False)
assert reactivated.status_code == 303
stored = asyncio.run(repository.list_spaces(repository.workspace.id))
assert stored[0].active is True
def test_deactivate_missing_space_is_a_stable_not_found() -> None:
app, _, _, _ = _fixture()
client = TestClient(app)
response = client.post(f"/admin/control/spaces/{uuid4()}/deactivate")
assert response.status_code == 404
assert "Knowledge space not found" in response.text
def test_space_actions_are_forbidden_for_an_unprivileged_principal() -> None:
app, repository, principal, _ = _fixture()
space = repository.workspace.create_knowledge_space(
id=uuid4(), name="Runbooks", slug="runbooks"
)
asyncio.run(repository.create_space(space))
viewer = Principal(
principal.id, principal.workspace_id, PrincipalType.HUMAN, frozenset({Role.VIEWER})
)
app.dependency_overrides[get_principal] = lambda: viewer
client = TestClient(app)
response = client.post(f"/admin/control/spaces/{space.id}/deactivate")
assert response.status_code == 403
assert "Access denied" in response.text
def test_upload_form_renders_for_a_real_space() -> None:
app, repository, _, _ = _fixture()
space = repository.workspace.create_knowledge_space(
id=uuid4(), name="Fleet Ops Procedures", slug="fleet-ops-procedures"
)
asyncio.run(repository.create_space(space))
client = TestClient(app)
response = client.get(f"/admin/control/spaces/{space.id}/documents/upload")
assert response.status_code == 200
assert "Upload a document to Fleet Ops Procedures" in response.text
assert 'enctype="multipart/form-data"' in response.text
def test_upload_form_missing_space_is_a_stable_not_found() -> None:
app, _, _, _ = _fixture()
client = TestClient(app)
response = client.get(f"/admin/control/spaces/{uuid4()}/documents/upload")
assert response.status_code == 404
assert "Knowledge space not found" in response.text
def test_upload_accepts_a_supported_file_and_enqueues_a_job() -> None:
app, repository, _, _ = _fixture()
space = repository.workspace.create_knowledge_space(
id=uuid4(), name="Fleet Ops Procedures", slug="fleet-ops-procedures"
)
asyncio.run(repository.create_space(space))
client = TestClient(app)
response = client.post(
f"/admin/control/spaces/{space.id}/documents/upload",
files={"file": ("runbook.txt", b"restart the gateway", "text/plain")},
)
assert response.status_code == 202
assert "Upload accepted" in response.text
assert "runbook.txt" in response.text
assert repository.uploads.calls == 1
assert repository.uploads.enqueued[0].operation == "ingest_upload"
def test_upload_rejects_an_unsupported_file_type_without_enqueuing() -> None:
app, repository, _, _ = _fixture()
space = repository.workspace.create_knowledge_space(
id=uuid4(), name="Fleet Ops Procedures", slug="fleet-ops-procedures"
)
asyncio.run(repository.create_space(space))
client = TestClient(app)
response = client.post(
f"/admin/control/spaces/{space.id}/documents/upload",
files={"file": ("payload.exe", b"MZ", "application/octet-stream")},
)
assert response.status_code == 415
assert "not supported" in response.text
assert repository.uploads.calls == 0
def test_upload_missing_space_is_a_stable_not_found() -> None:
app, _, _, _ = _fixture()
client = TestClient(app)
response = client.post(
f"/admin/control/spaces/{uuid4()}/documents/upload",
files={"file": ("runbook.txt", b"restart the gateway", "text/plain")},
)
assert response.status_code == 404
assert "Knowledge space not found" in response.text
def test_upload_is_forbidden_for_an_unprivileged_principal() -> None:
app, repository, principal, _ = _fixture()
space = repository.workspace.create_knowledge_space(
id=uuid4(), name="Fleet Ops Procedures", slug="fleet-ops-procedures"
)
asyncio.run(repository.create_space(space))
viewer = Principal(
principal.id, principal.workspace_id, PrincipalType.HUMAN, frozenset({Role.VIEWER})
)
app.dependency_overrides[get_principal] = lambda: viewer
client = TestClient(app)
response = client.post(
f"/admin/control/spaces/{space.id}/documents/upload",
files={"file": ("runbook.txt", b"restart the gateway", "text/plain")},
)
assert response.status_code == 403
assert "Access denied" in response.text
assert repository.uploads.calls == 0
+163
View File
@@ -0,0 +1,163 @@
from __future__ import annotations
from datetime import UTC, datetime
from uuid import uuid4
from fastapi.testclient import TestClient
from ragcore.api.v1.control.dependencies import get_principal
from ragcore.application.profiles import (
ActivationDecision,
ActivationDecisionNotFoundError,
AlreadyRolledBackError,
CandidateAliasTarget,
NotActivatedError,
)
from ragcore.domain.authorization import Principal, PrincipalType
from ragcore.domain.control import Role
from ragcore.evaluation import RetrievalRunProfile
from ragcore.evaluation.metrics.models import GateResult
from ragcore.main import create_app
from ragcore.web.profiles.dependencies import get_profile_activation_service
WORKSPACE_ID = uuid4()
def _principal(role: Role) -> Principal:
return Principal(uuid4(), WORKSPACE_ID, PrincipalType.HUMAN, frozenset({role}))
def _run_profile(version: str) -> RetrievalRunProfile:
return RetrievalRunProfile(
embedding_profile_digest="a" * 64,
sparse_profile_version="technical-v1",
index_alias="rag_dense_hybrid_active",
index_collection_version=version,
)
def _decision(**overrides: object) -> ActivationDecision:
values: dict[str, object] = {
"id": uuid4(),
"created_at": datetime.now(UTC),
"dataset_id": "sample",
"dataset_version": "v1",
"baseline_run_id": uuid4(),
"candidate_run_id": uuid4(),
"baseline_profile": _run_profile("v1"),
"candidate_profile": _run_profile("v2"),
"gate": GateResult(thresholds_version="v1", passed=True, regressions=()),
"activated": True,
"candidate_target": CandidateAliasTarget(
alias_name="rag_dense_hybrid_active",
collection_name="rag_dense_hybrid_v2",
version="v2",
model_digest="b" * 64,
),
"index_operation_id": uuid4(),
"previous_collection": "rag_dense_hybrid_v1",
}
values.update(overrides)
return ActivationDecision(**values)
class StubProfileActivationService:
def __init__(self, decisions: tuple[ActivationDecision, ...] = ()) -> None:
self._decisions = decisions
self.rollback_calls: list[object] = []
self.rollback_error: Exception | None = None
async def list_recent(self, limit: int = 20) -> tuple[ActivationDecision, ...]:
return self._decisions[:limit]
async def rollback(self, decision_id: object) -> ActivationDecision:
self.rollback_calls.append(decision_id)
if self.rollback_error is not None:
raise self.rollback_error
return self._decisions[0].with_rollback(rolled_back_at=datetime.now(UTC))
def _app(service: StubProfileActivationService, principal: Principal) -> TestClient:
app = create_app()
app.dependency_overrides[get_principal] = lambda: principal
app.dependency_overrides[get_profile_activation_service] = lambda: service
return TestClient(app, raise_server_exceptions=False)
def test_page_loads_with_landmarks_and_empty_state_for_platform_admin() -> None:
client = _app(StubProfileActivationService(), _principal(Role.PLATFORM_ADMIN))
response = client.get("/admin/profiles")
assert response.status_code == 200
assert 'href="#main-content"' in response.text
assert "No profile activation decisions have been recorded yet." in response.text
def test_non_platform_admin_is_forbidden() -> None:
client = _app(StubProfileActivationService(), _principal(Role.WORKSPACE_ADMIN))
response = client.get("/admin/profiles")
assert response.status_code == 403
assert "Access denied" in response.text
def test_unauthenticated_request_is_rejected() -> None:
app = create_app()
stub = StubProfileActivationService()
app.dependency_overrides[get_profile_activation_service] = lambda: stub
client = TestClient(app, raise_server_exceptions=False)
response = client.get("/admin/profiles")
assert response.status_code == 401
def test_decision_list_shows_gate_and_status_without_leaking_secrets() -> None:
decision = _decision()
service = StubProfileActivationService((decision,))
client = _app(service, _principal(Role.PLATFORM_ADMIN))
response = client.get("/admin/profiles")
assert response.status_code == 200
assert "v1" in response.text and "v2" in response.text
assert "passed" in response.text
assert "activated" in response.text
assert "api_key" not in response.text.lower()
assert "secret" not in response.text.lower()
def test_rollback_succeeds_for_platform_admin() -> None:
decision = _decision()
service = StubProfileActivationService((decision,))
client = _app(service, _principal(Role.PLATFORM_ADMIN))
response = client.post(f"/admin/profiles/{decision.id}/rollback")
assert response.status_code == 200
assert service.rollback_calls == [decision.id]
def test_rollback_is_forbidden_for_non_platform_admin() -> None:
decision = _decision()
service = StubProfileActivationService((decision,))
client = _app(service, _principal(Role.WORKSPACE_ADMIN))
response = client.post(f"/admin/profiles/{decision.id}/rollback")
assert response.status_code == 403
assert service.rollback_calls == []
def test_rollback_of_unknown_decision_is_a_stable_not_found() -> None:
service = StubProfileActivationService((_decision(),))
service.rollback_error = ActivationDecisionNotFoundError("not found")
client = _app(service, _principal(Role.PLATFORM_ADMIN))
response = client.post(f"/admin/profiles/{uuid4()}/rollback")
assert response.status_code == 404
def test_rollback_of_a_rejected_decision_is_a_stable_conflict() -> None:
service = StubProfileActivationService((_decision(),))
service.rollback_error = NotActivatedError("never activated")
client = _app(service, _principal(Role.PLATFORM_ADMIN))
response = client.post(f"/admin/profiles/{uuid4()}/rollback")
assert response.status_code == 409
def test_rollback_twice_is_a_stable_conflict() -> None:
service = StubProfileActivationService((_decision(),))
service.rollback_error = AlreadyRolledBackError("already rolled back")
client = _app(service, _principal(Role.PLATFORM_ADMIN))
response = client.post(f"/admin/profiles/{uuid4()}/rollback")
assert response.status_code == 409
@@ -0,0 +1,246 @@
"""Query Lab productization: selector-first form, no stale capability copy,
reranking shown only when active, fused-stage explainability."""
from __future__ import annotations
from uuid import uuid4
from fastapi.testclient import TestClient
from ragcore.api.v1.control.dependencies import get_principal
from ragcore.domain.authorization import Principal, PrincipalType
from ragcore.domain.control import Role
from ragcore.main import create_app
from ragcore.web.query_lab.dependencies import get_query_lab_service
from ragcore.web.query_lab.models import (
AnswerabilityTrace,
CandidateBackendLabel,
CandidateTrace,
CitationTrace,
ContextTrace,
EffectiveFilterTrace,
FusionTrace,
InclusionState,
ParentExpansionTrace,
QueryLabQuery,
QueryLabTrace,
RerankTrace,
RevisionTrace,
)
from ragcore.web.query_lab.routes import QueryLabCatalog, get_query_lab_catalog
WORKSPACE_ID = uuid4()
SPACE_ID = uuid4()
SOURCE_ID = uuid4()
DOCUMENT_ID = uuid4()
class StubService:
def __init__(self, trace: QueryLabTrace) -> None:
self.trace = trace
self.calls: list[QueryLabQuery] = []
def can_use(self, principal: Principal) -> bool:
return True
async def run(self, principal: Principal, query: QueryLabQuery) -> QueryLabTrace:
self.calls.append(query)
return self.trace
def _fused_candidate() -> CandidateTrace:
return CandidateTrace(
rank=1,
chunk_id=uuid4(),
document_id=DOCUMENT_ID,
space_id=SPACE_ID,
backend=CandidateBackendLabel.FUSED,
score=0.0325,
score_label="rrf_score_not_a_probability",
content_type="text/markdown",
trust_level="trusted_internal",
language="en",
text_preview="restart the service after the breaker",
text_truncated=False,
inclusion=InclusionState.INCLUDED,
reason="fused_rank",
dense_rank=2,
dense_score=0.87,
sparse_rank=1,
sparse_score=12.5,
rrf_dense=1 / 62,
rrf_sparse=1 / 61,
document_title="Gateway runbook",
source_name="Infra runbooks",
)
def _trace(*, rerank_state: str = "skipped") -> QueryLabTrace:
return QueryLabTrace(
retrieval_run_id=uuid4(),
query="restart breaker",
profile="hybrid-v1",
effective_filters=EffectiveFilterTrace(
requested_space_ids=(SPACE_ID,),
effective_space_ids=(SPACE_ID,),
denied_space_ids=(),
trust_required_space_ids=(),
requested_content_types=(),
applied_content_types=(),
requested_languages=("en",),
applied_languages=("en",),
unsupported_filter_fields=(),
),
dense_candidates=(),
sparse_candidates=(),
fusion=FusionTrace(candidates=(_fused_candidate(),), suppressed_count=1),
rerank=RerankTrace(
state=rerank_state, degradation_code=None, candidates=(), elapsed_ms=0.0
),
parent_expansion=ParentExpansionTrace(1, 0, 40),
context=ContextTrace(
token_count=120, max_context_tokens=4000, block_count=1, citation_ids=()
),
answerability=AnswerabilityTrace(
status="answerable",
reasons=("sufficient_evidence",),
evidence_count=1,
document_diversity=1,
source_independence=1,
facet_coverage_ratio=1.0,
thresholds_version="v1",
),
citations=(
CitationTrace(
id=uuid4(),
document_id=DOCUMENT_ID,
chunk_id=uuid4(),
excerpt_preview="restart the service after the breaker",
excerpt_truncated=False,
location={"section": "Failover", "line_start": 12, "line_end": 14},
source_uri=f"ragcore://source/{SOURCE_ID}",
document_title="Gateway runbook",
source_name="Infra runbooks",
display="Gateway runbook · Failover · lines 12-14",
),
),
timings_ms={"embed_query": 18.0, "dense_search": 8.0, "sparse_search": 6.0, "fusion": 1.0},
revisions=RevisionTrace("hybrid/v1", None, "technical/v1", "rag_dense_hybrid_active", "v1"),
degraded=False,
degradation_codes=(),
)
def _catalog() -> QueryLabCatalog:
return QueryLabCatalog(
spaces=((SPACE_ID, "Production Knowledge Base"),),
sources=((SOURCE_ID, "Infra runbooks", "Production Knowledge Base"),),
documents=((DOCUMENT_ID, "Gateway runbook", "Production Knowledge Base"),),
languages=("de", "en", "fr", "nl"),
content_types=("text/markdown", "text/plain"),
trust_levels=("trusted_internal", "user_uploaded"),
)
def _client(service: StubService, catalog: QueryLabCatalog | None = None) -> TestClient:
app = create_app()
principal = Principal(
uuid4(), WORKSPACE_ID, PrincipalType.HUMAN, frozenset({Role.SPACE_MANAGER})
)
app.dependency_overrides[get_principal] = lambda: principal
app.dependency_overrides[get_query_lab_service] = lambda: service
app.dependency_overrides[get_query_lab_catalog] = lambda: catalog or _catalog()
return TestClient(app)
def test_form_offers_selectors_from_the_catalog_and_an_advanced_section() -> None:
client = _client(StubService(_trace()))
body = client.get("/admin/query-lab").text
assert "Production Knowledge Base" in body
assert "Infra runbooks" in body
assert "Gateway runbook" in body
assert '<select id="space_ids" name="space_ids" multiple' in body
assert '<select id="source_ids" name="source_ids" multiple' in body
assert '<select id="document_ids" name="document_ids" multiple' in body
assert '<select id="languages" name="languages" multiple' in body
assert '<select id="trust_levels" name="trust_levels" multiple' in body
assert '<select id="profile" name="profile"' in body
assert "Advanced: raw identifiers" in body
# Stale copy is gone.
assert "Narrowing only" not in body
assert "not yet applied server-side" not in body
assert "not yet supported by the filter compiler" not in body
def test_selected_values_become_server_side_filters() -> None:
service = StubService(_trace())
client = _client(service)
response = client.post(
"/admin/query-lab/run",
data={
"query": "restart breaker",
"profile": "hybrid-v1",
"max_results": 5,
"space_ids": [str(SPACE_ID)],
"source_ids": [str(SOURCE_ID)],
"document_ids": [str(DOCUMENT_ID)],
"languages": ["en", "nl"],
"trust_levels": ["trusted_internal"],
},
)
assert response.status_code == 200
[query] = service.calls
assert query.requested_space_ids == (SPACE_ID,)
assert query.filters.source_ids == (SOURCE_ID,)
assert query.filters.document_ids == (DOCUMENT_ID,)
assert query.filters.languages == ("en", "nl")
assert query.filters.trust_levels == ("trusted_internal",)
def test_advanced_raw_ids_merge_with_selectors() -> None:
service = StubService(_trace())
client = _client(service)
extra_source = uuid4()
response = client.post(
"/admin/query-lab/run",
data={
"query": "restart breaker",
"source_ids": [str(SOURCE_ID)],
"raw_source_ids": f"{extra_source}, {SOURCE_ID}",
},
)
assert response.status_code == 200
[query] = service.calls
assert set(query.filters.source_ids) == {SOURCE_ID, extra_source}
assert len(query.filters.source_ids) == 2
def test_inspector_explains_fused_ranking_and_hides_inactive_reranking() -> None:
client = _client(StubService(_trace()))
body = client.post("/admin/query-lab/run", data={"query": "restart breaker"}).text
assert "Retrieval inspector" in body
assert "Fusion — RRF ranking" in body
assert "Final rank" in body
assert "#2 · 0.870" in body # dense rank + score
assert "#1 · 12.500" in body # sparse rank + score
assert "+0.0161" in body # RRF contribution 1/62
assert "Gateway runbook" in body and "Infra runbooks" in body
assert "Gateway runbook · Failover · lines 12-14" in body
assert "no reranker is active" in body
assert "Reranking (" not in body
assert "Reranker profile" not in body
assert "Generation is not run by Query Lab" in body
assert "18.0 ms" in body and "embed_query" in body
def test_reranking_section_appears_only_when_the_stage_is_active() -> None:
client = _client(StubService(_trace(rerank_state="reranked")))
body = client.post("/admin/query-lab/run", data={"query": "restart breaker"}).text
assert "Reranking (reranked)" in body
def test_unavailable_catalog_degrades_to_advanced_fields() -> None:
client = _client(StubService(_trace()), QueryLabCatalog(available=False, languages=("en",)))
body = client.get("/admin/query-lab").text
assert "Selector lists could not be loaded" in body
assert 'name="requested_space_ids"' in body
+306
View File
@@ -0,0 +1,306 @@
from __future__ import annotations
from uuid import uuid4
from fastapi.testclient import TestClient
from ragcore.api.v1.control.dependencies import get_principal
from ragcore.api.v1.search.service import AuthorizationInputs
from ragcore.application.authorization import AuthorizationService
from ragcore.application.retrieval.authorization import RetrievalAuthorizationService
from ragcore.domain.authorization import Principal, PrincipalType
from ragcore.domain.control import Role
from ragcore.main import create_app
from ragcore.web.query_lab.dependencies import get_query_lab_service
from ragcore.web.query_lab.models import (
AnswerabilityTrace,
CandidateBackendLabel,
CandidateTrace,
CitationTrace,
ContextTrace,
EffectiveFilterTrace,
FusionTrace,
InclusionState,
ParentExpansionTrace,
QueryLabQuery,
QueryLabTrace,
RerankTrace,
RevisionTrace,
)
from ragcore.web.query_lab.service import QueryLabService
WORKSPACE_ID = uuid4()
SPACE_ID = uuid4()
DOCUMENT_ID = uuid4()
class StubQueryLabService:
def __init__(self, trace: QueryLabTrace | None = None, error: Exception | None = None) -> None:
self._trace = trace
self._error = error
self.calls: list[QueryLabQuery] = []
def can_use(self, principal: Principal) -> bool:
return True
async def run(self, principal: Principal, query: QueryLabQuery) -> QueryLabTrace:
self.calls.append(query)
if self._error is not None:
raise self._error
assert self._trace is not None
return self._trace
def _principal(role: Role) -> Principal:
return Principal(uuid4(), WORKSPACE_ID, PrincipalType.HUMAN, frozenset({role}))
def _candidate(text_preview: str = "hello world", **overrides: object) -> CandidateTrace:
values: dict[str, object] = {
"rank": 1,
"chunk_id": uuid4(),
"document_id": DOCUMENT_ID,
"space_id": SPACE_ID,
"backend": CandidateBackendLabel.DENSE,
"score": 0.42,
"score_label": "similarity_score",
"content_type": "text/plain",
"trust_level": "source",
"language": "en",
"text_preview": text_preview,
"text_truncated": False,
"inclusion": InclusionState.INCLUDED,
"reason": "selected_for_fusion",
}
values.update(overrides)
return CandidateTrace(**values)
def _trace(**overrides: object) -> QueryLabTrace:
values: dict[str, object] = {
"retrieval_run_id": uuid4(),
"query": "what does the runbook say",
"profile": "hybrid-v1",
"effective_filters": EffectiveFilterTrace(
requested_space_ids=(SPACE_ID,),
effective_space_ids=(SPACE_ID,),
denied_space_ids=(),
trust_required_space_ids=(),
requested_content_types=(),
applied_content_types=(),
requested_languages=(),
applied_languages=(),
unsupported_filter_fields=(),
),
"dense_candidates": (_candidate(),),
"sparse_candidates": (),
"fusion": FusionTrace(
candidates=(_candidate(backend=CandidateBackendLabel.FUSED),), suppressed_count=0
),
"rerank": RerankTrace(
state="reranked", degradation_code=None, candidates=(), elapsed_ms=12.0
),
"parent_expansion": ParentExpansionTrace(0, 0, 0),
"context": ContextTrace(
token_count=10, max_context_tokens=4000, block_count=1, citation_ids=()
),
"answerability": AnswerabilityTrace(
status="answerable",
reasons=("sufficient_evidence",),
evidence_count=2,
document_diversity=2,
source_independence=2,
facet_coverage_ratio=1.0,
thresholds_version="v1",
),
"citations": (
CitationTrace(
id=uuid4(),
document_id=DOCUMENT_ID,
chunk_id=uuid4(),
excerpt_preview="the runbook says to restart the service",
excerpt_truncated=False,
location={"page": 1},
source_uri="ragcore://source/abc",
),
),
"timings_ms": {"embed_query": 5.0, "dense_search": 3.0},
"revisions": RevisionTrace(
"hybrid/v1", "query-lab/v1", "technical/v1", "rag_dense_hybrid_active", "v1"
),
"degraded": False,
"degradation_codes": (),
}
values.update(overrides)
return QueryLabTrace(**values)
def _app(service: StubQueryLabService, principal: Principal) -> TestClient:
app = create_app()
app.dependency_overrides[get_principal] = lambda: principal
app.dependency_overrides[get_query_lab_service] = lambda: service
return TestClient(app, raise_server_exceptions=False)
def test_unauthenticated_request_is_rejected_without_reaching_the_service() -> None:
service = StubQueryLabService(_trace())
app = create_app()
app.dependency_overrides[get_query_lab_service] = lambda: service
client = TestClient(app, raise_server_exceptions=False)
response = client.post(
"/admin/query-lab/run",
data={"query": "test", "profile": "hybrid-v1", "max_results": 10},
)
assert response.status_code == 401
assert service.calls == []
def test_page_loads_with_accessible_landmarks_and_empty_state() -> None:
client = _app(StubQueryLabService(), _principal(Role.SPACE_MANAGER))
response = client.get("/admin/query-lab")
assert response.status_code == 200
assert 'href="#main-content"' in response.text
assert '<nav aria-label="Primary navigation">' in response.text
assert "Run a query above" in response.text
class UnusableStubQueryLabService(StubQueryLabService):
def can_use(self, principal: Principal) -> bool:
return False
def test_get_page_is_also_forbidden_for_an_unprivileged_principal() -> None:
client = _app(UnusableStubQueryLabService(), _principal(Role.VIEWER))
response = client.get("/admin/query-lab")
assert response.status_code == 403
assert "Access denied" in response.text
class DenyingInputsProvider:
async def load(self, principal: Principal) -> AuthorizationInputs:
return AuthorizationInputs(spaces=(), grants=(), user_grants=(), application=None)
class ExplodingExecutor:
async def execute(self, request): # pragma: no cover - must never be reached
raise AssertionError("executor must not run for a denied principal")
def test_viewer_role_is_forbidden_and_leaks_nothing() -> None:
real_service = QueryLabService(
authorization=AuthorizationService(),
retrieval_authorization=RetrievalAuthorizationService(),
inputs=DenyingInputsProvider(),
executor=ExplodingExecutor(),
)
client = _app(real_service, _principal(Role.VIEWER))
response = client.post(
"/admin/query-lab/run",
data={"query": "secret question", "profile": "hybrid-v1", "max_results": 10},
)
assert response.status_code == 403
assert "Access denied" in response.text
assert "secret question" not in response.text
assert "runbook" not in response.text
def test_happy_path_shows_all_pipeline_phases() -> None:
service = StubQueryLabService(_trace())
client = _app(service, _principal(Role.SPACE_MANAGER))
response = client.post(
"/admin/query-lab/run",
data={"query": "what does the runbook say", "profile": "hybrid-v1", "max_results": 10},
)
assert response.status_code == 200
body = response.text
assert "Effective authorization" in body
assert "Answer &amp; answerability" in body or "Answer" in body
assert "answerable" in body
assert "a category, not a confidence percentage" in body
assert "not a probability" in body or "similarity_score" in body
assert "the runbook says to restart the service" in body
assert service.calls[0].query == "what does the runbook say"
assert 'aria-label="Run summary"' in body
assert "Evidence count" in body
assert "8.0 ms" in body # sum of the fixture's real embed_query + dense_search timings
def test_malicious_candidate_text_is_escaped_not_executed() -> None:
malicious = "<script>alert('xss')</script>"
trace = _trace(dense_candidates=(_candidate(text_preview=malicious),))
client = _app(StubQueryLabService(trace), _principal(Role.SPACE_MANAGER))
response = client.post(
"/admin/query-lab/run",
data={"query": "test", "profile": "hybrid-v1", "max_results": 10},
)
assert response.status_code == 200
assert "<script>alert" not in response.text
assert "&lt;script&gt;" in response.text
def test_degraded_run_shows_a_visible_non_color_only_banner() -> None:
trace = _trace(degraded=True, degradation_codes=("no_active_embedding_profile",))
client = _app(StubQueryLabService(trace), _principal(Role.SPACE_MANAGER))
response = client.post(
"/admin/query-lab/run",
data={"query": "test", "profile": "hybrid-v1", "max_results": 10},
)
assert response.status_code == 200
assert "Degraded run" in response.text
assert "no_active_embedding_profile" in response.text
assert 'role="alert"' in response.text
def test_oversized_query_is_rejected_before_reaching_the_service() -> None:
service = StubQueryLabService(_trace())
client = _app(service, _principal(Role.SPACE_MANAGER))
response = client.post(
"/admin/query-lab/run",
data={"query": "x" * 8001, "profile": "hybrid-v1", "max_results": 10},
)
assert response.status_code == 422
assert service.calls == []
def test_invalid_requested_space_id_is_a_stable_bad_request() -> None:
service = StubQueryLabService(_trace())
client = _app(service, _principal(Role.SPACE_MANAGER))
response = client.post(
"/admin/query-lab/run",
data={
"query": "test",
"profile": "hybrid-v1",
"max_results": 10,
"requested_space_ids": "not-a-uuid",
},
)
assert response.status_code == 400
assert service.calls == []
def test_response_never_contains_secret_or_credential_markers() -> None:
client = _app(StubQueryLabService(_trace()), _principal(Role.SPACE_MANAGER))
response = client.post(
"/admin/query-lab/run",
data={"query": "test", "profile": "hybrid-v1", "max_results": 10},
)
body_lower = response.text.lower()
markers = (
"api_key",
"api_token_pepper",
"secret_key",
"authorization: bearer",
"qdrant_api_key",
)
for marker in markers:
assert marker not in body_lower
def test_response_never_contains_a_raw_embedding_vector_shape() -> None:
client = _app(StubQueryLabService(_trace()), _principal(Role.SPACE_MANAGER))
response = client.post(
"/admin/query-lab/run",
data={"query": "test", "profile": "hybrid-v1", "max_results": 10},
)
assert "dense_vector" not in response.text
assert "sparse_indices" not in response.text
+150
View File
@@ -0,0 +1,150 @@
"""'/admin/dashboard': real, never-fabricated per-section workspace counts."""
from __future__ import annotations
from uuid import uuid4
from fastapi.testclient import TestClient
from ragcore.api.v1.control.dependencies import get_control_application, get_principal
from ragcore.application.authorization import AuthorizationService
from ragcore.application.control.api import ControlPlaneApplication
from ragcore.domain.authorization import Principal, PrincipalType
from ragcore.domain.control import Application, KnowledgeSpace, Policy, Role, Workspace
from ragcore.main import create_app
class FakeControlRepository:
def __init__(self, workspace: Workspace) -> None:
self.workspace = workspace
self.applications: list[Application] = []
self.spaces: list[KnowledgeSpace] = []
self.policies: list[Policy] = []
self.grants: list[object] = []
async def get_workspace(self, workspace_id: object) -> Workspace | None:
return self.workspace if workspace_id == self.workspace.id else None
async def list_applications(self, workspace_id: object) -> tuple[Application, ...]:
return tuple(self.applications)
async def list_spaces(self, workspace_id: object) -> tuple[KnowledgeSpace, ...]:
return tuple(self.spaces)
async def list_policies(self, workspace_id: object) -> tuple[Policy, ...]:
return tuple(self.policies)
async def list_grants(self, workspace_id: object) -> tuple[object, ...]:
return tuple(self.grants)
def _client(principal: Principal, repository: FakeControlRepository) -> TestClient:
service = ControlPlaneApplication(repository, AuthorizationService())
app = create_app()
app.dependency_overrides[get_principal] = lambda: principal
app.dependency_overrides[get_control_application] = lambda: service
return TestClient(app, raise_server_exceptions=False)
def test_dashboard_requires_authentication() -> None:
client = TestClient(create_app(), raise_server_exceptions=False)
response = client.get("/admin/dashboard")
assert response.status_code == 401
def test_dashboard_shows_real_counts_for_a_workspace_admin() -> None:
workspace = Workspace(uuid4(), "Dash workspace", "dash-workspace")
principal = Principal(
uuid4(), workspace.id, PrincipalType.HUMAN, frozenset({Role.WORKSPACE_ADMIN})
)
repository = FakeControlRepository(workspace)
repository.applications.append(
workspace.create_application(id=uuid4(), name="Ingest", slug="ingest")
)
client = _client(principal, repository)
response = client.get("/admin/dashboard")
assert response.status_code == 200
assert 'href="#main-content"' in response.text
assert '<nav aria-label="Primary navigation">' in response.text
assert "registered application</p>" in response.text
assert "Not configured" in response.text
def test_dashboard_presents_truthful_source_to_answer_lifecycle() -> None:
workspace = Workspace(uuid4(), "Flow workspace", "flow-workspace")
principal = Principal(
uuid4(), workspace.id, PrincipalType.HUMAN, frozenset({Role.WORKSPACE_ADMIN})
)
repository = FakeControlRepository(workspace)
response = _client(principal, repository).get("/admin/dashboard")
assert response.status_code == 200
assert 'data-shell-title="Dashboard"' in response.text
assert 'data-rag-lifecycle="source-to-answer"' in response.text
assert 'href="/admin/sources"' in response.text
assert 'href="/admin/jobs"' in response.text
assert 'href="/admin/query-lab"' in response.text
assert 'href="/admin/control/applications"' in response.text
assert "Dense + sparse" in response.text
assert "RRF fusion" in response.text
assert "versioned citations" in response.text
assert "reranking" not in response.text.lower()
def test_product_styles_define_tokens_responsiveness_and_reduced_motion() -> None:
client = TestClient(create_app())
response = client.get("/static/admin.css")
assert response.status_code == 200
assert "--color-accent:" in response.text
assert ".lifecycle-grid" in response.text
assert "@media (max-width: 767px)" in response.text
assert "@media (prefers-reduced-motion: reduce)" in response.text
assert "animation-duration: 0.01ms" in response.text
script = client.get("/static/admin.js")
assert script.status_code == 200
assert 'matchMedia("(min-width: 1024px)")' in script.text
assert 'toggleAttribute("inert"' in script.text
assert 'addEventListener("change"' in script.text
def test_dashboard_marks_sections_restricted_for_an_unprivileged_principal() -> None:
workspace = Workspace(uuid4(), "Dash workspace", "dash-workspace")
principal = Principal(uuid4(), workspace.id, PrincipalType.HUMAN, frozenset({Role.VIEWER}))
repository = FakeControlRepository(workspace)
client = _client(principal, repository)
response = client.get("/admin/dashboard")
assert response.status_code == 200
assert "You are not authorized to view applications." in response.text
assert "You are not authorized to view knowledge spaces." in response.text
assert "You are not authorized to view policies." in response.text
assert "Restricted to platform administrators." in response.text
class _StubProfileActivationService:
async def list_recent(self, limit: int = 1) -> tuple[object, ...]:
return ()
def test_dashboard_shows_empty_state_for_a_workspace_with_nothing_yet() -> None:
workspace = Workspace(uuid4(), "Empty workspace", "empty-workspace")
principal = Principal(
uuid4(), workspace.id, PrincipalType.HUMAN, frozenset({Role.PLATFORM_ADMIN})
)
repository = FakeControlRepository(workspace)
service = ControlPlaneApplication(repository, AuthorizationService())
app = create_app()
app.dependency_overrides[get_principal] = lambda: principal
app.dependency_overrides[get_control_application] = lambda: service
app.state.profile_activation_service = _StubProfileActivationService()
client = TestClient(app, raise_server_exceptions=False)
response = client.get("/admin/dashboard")
assert response.status_code == 200
assert "No profile activation decisions have been recorded yet." in response.text
+532
View File
@@ -0,0 +1,532 @@
"""Global Documents, Ingestion Jobs (detail/retry) and System Health screens
render real state and enforce role gates."""
from __future__ import annotations
from datetime import UTC, datetime, timedelta
from uuid import UUID, uuid4
from fastapi.testclient import TestClient
from ragcore.api.v1.control.dependencies import get_control_application, get_principal
from ragcore.application.documents import (
ArtifactRecord,
ChunkRecord,
DocumentDetail,
DocumentFailureCode,
DocumentListFilter,
DocumentListPage,
DocumentRecord,
DocumentStatusRecord,
DocumentVersionRecord,
DocumentVersionState,
)
from ragcore.application.jobs import Job, JobAttempt, JobListFilter, JobListPage, JobStatus
from ragcore.application.sources import SourceRecord
from ragcore.domain.authorization import Principal, PrincipalType
from ragcore.domain.control import KnowledgeSpace, Role
from ragcore.domain.sources import ConnectorKind
from ragcore.main import create_app
from ragcore.web.documents import get_source_registry
WORKSPACE_ID = uuid4()
SPACE_ID = uuid4()
SOURCE_ID = uuid4()
JOB_ID = uuid4()
def _principal(role: Role = Role.WORKSPACE_ADMIN) -> Principal:
return Principal(uuid4(), WORKSPACE_ID, PrincipalType.HUMAN, frozenset({role}))
class FakeRegistry:
def __init__(self) -> None:
self.source = SourceRecord(
id=SOURCE_ID,
workspace_id=WORKSPACE_ID,
space_id=SPACE_ID,
name="Infra runbooks",
kind=ConnectorKind.GIT,
)
async def get_sources(
self, source_ids: tuple[UUID, ...], *, workspace_id: UUID | None = None
) -> dict[UUID, SourceRecord]:
if workspace_id is not None and self.source.workspace_id != workspace_id:
return {}
return {SOURCE_ID: self.source} if SOURCE_ID in source_ids else {}
async def get_source(self, source_id: UUID) -> SourceRecord | None:
return self.source if source_id == SOURCE_ID else None
async def get_owned_source(
self, source_id: UUID, *, workspace_id: UUID, space_id: UUID | None = None
) -> SourceRecord | None:
if source_id != SOURCE_ID or workspace_id != WORKSPACE_ID:
return None
if space_id is not None and space_id != SPACE_ID:
return None
return self.source
class FakeControl:
def __init__(self) -> None:
self.document = DocumentRecord(
id=uuid4(),
workspace_id=WORKSPACE_ID,
space_id=SPACE_ID,
source_key=str(SOURCE_ID),
external_id="runbooks/backup.md",
title="Backup runbook",
source_id=SOURCE_ID,
)
self.failed_document = DocumentRecord(
id=uuid4(),
workspace_id=WORKSPACE_ID,
space_id=SPACE_ID,
source_key=str(SOURCE_ID),
external_id="broken.pdf",
title="Broken scan",
source_id=SOURCE_ID,
)
self.version = DocumentVersionRecord(
id=uuid4(),
document_id=self.document.id,
source_fingerprint="a" * 64,
content_hash="b" * 64,
parser_version="text-parser-1",
chunk_profile_version="prose-v1",
state=DocumentVersionState.PUBLISHED,
created_at=datetime(2026, 8, 20, 9, 0, tzinfo=UTC),
job_id=JOB_ID,
source_revision="3fc821a9bd",
)
self.failed_version = DocumentVersionRecord(
id=uuid4(),
document_id=self.failed_document.id,
source_fingerprint="c" * 64,
content_hash="c" * 64,
parser_version="none",
chunk_profile_version="none",
state=DocumentVersionState.FAILED,
created_at=datetime(2026, 8, 20, 9, 5, tzinfo=UTC),
job_id=uuid4(),
failure_code=DocumentFailureCode.SECURITY_QUARANTINED.value,
failure_retryable=False,
failed_at=datetime(2026, 8, 20, 9, 6, tzinfo=UTC),
)
async def list_spaces(self, principal: Principal) -> tuple[KnowledgeSpace, ...]:
return (
KnowledgeSpace(
id=SPACE_ID, workspace_id=WORKSPACE_ID, name="Runbooks space", slug="runbooks"
),
)
async def list_workspace_documents(self, principal: Principal, filters: DocumentListFilter):
items = [
DocumentStatusRecord(
document=self.document,
latest_state=DocumentVersionState.PUBLISHED,
parser_version="text-parser-1",
chunk_profile_version="prose-v1",
updated_at=datetime(2026, 8, 20, 9, 0, tzinfo=UTC),
),
DocumentStatusRecord(
document=self.failed_document,
latest_state=DocumentVersionState.FAILED,
parser_version="none",
chunk_profile_version="none",
updated_at=datetime(2026, 8, 20, 9, 6, tzinfo=UTC),
failure_code=DocumentFailureCode.SECURITY_QUARANTINED.value,
failure_retryable=False,
),
]
if filters.state == "failed":
items = [item for item in items if item.failed]
if filters.search:
items = [
item for item in items if filters.search.lower() in item.document.title.lower()
]
return DocumentListPage(items=tuple(items), total=len(items), limit=filters.limit, offset=0)
async def get_document_detail(
self, principal: Principal, document_id: UUID, *, version_id: UUID | None = None
):
if document_id == self.document.id:
chunk = ChunkRecord(
id=uuid4(),
document_version_id=self.version.id,
structure_path="doc/section[1]/p[2]",
content_hash="d" * 64,
chunk_profile_version="prose-v1",
content="Run the nightly snapshot SNAP-22 before midnight.",
token_count=9,
metadata={
"role": "child",
"section": "Nightly snapshot",
"line_start": 12,
"line_end": 14,
"content_type": "text/markdown",
"language": "en",
"trust_level": "trusted_internal",
},
)
return DocumentDetail(
document=self.document,
versions=(self.version,),
shown_version=self.version,
chunks=(chunk,),
artifacts=(
ArtifactRecord(
id=uuid4(),
document_version_id=self.version.id,
kind="canonical",
content_hash="e" * 64,
storage_key="parsed/ee",
size_bytes=1234,
),
),
)
if document_id == self.failed_document.id:
return DocumentDetail(
document=self.failed_document,
versions=(self.failed_version,),
shown_version=self.failed_version,
chunks=(),
artifacts=(),
)
raise LookupError("document not found")
async def get_document_by_source(
self, workspace_id: UUID, source_key: str, external_id: str
) -> DocumentRecord | None:
if (
workspace_id == WORKSPACE_ID
and source_key == str(SOURCE_ID)
and external_id == self.document.external_id
):
return self.document
return None
class FakeJobRepository:
def __init__(self) -> None:
now = datetime.now(UTC)
self.jobs: dict[UUID, Job] = {
JOB_ID: Job(
id=JOB_ID,
workspace_id=WORKSPACE_ID,
job_key="k1",
operation="ingest_upload",
target_key="digest",
profile_version="upload-v1",
payload={
"original_name": "backup.md",
"external_id": "runbooks/backup.md",
"source_id": str(SOURCE_ID),
"workspace_id": str(WORKSPACE_ID),
"space_id": str(SPACE_ID),
"media_type": "text/markdown",
},
status=JobStatus.TERMINAL,
available_at=now - timedelta(minutes=5),
attempt_count=3,
last_error_code="retryable_error",
last_error_details={"failure_code": "embedding_failed"},
)
}
self.requeued: list[UUID] = []
self.scopes: list[UUID | None] = []
self.fail_requeue_race = False
async def list_jobs(
self, *, workspace_id: UUID | None, filters: JobListFilter
) -> JobListPage:
self.scopes.append(workspace_id)
matching = [
job
for job in self.jobs.values()
if (workspace_id is None or job.workspace_id == workspace_id)
and (filters.status is None or job.status is filters.status)
and (filters.operation is None or job.operation == filters.operation)
]
return JobListPage(
items=tuple(matching[filters.offset : filters.offset + filters.limit]),
total=len(matching),
limit=filters.limit,
offset=filters.offset,
)
async def status_counts(self, *, workspace_id: UUID | None) -> dict[str, int]:
self.scopes.append(workspace_id)
return {"terminal": 1}
async def get(self, job_id: UUID) -> Job | None:
return self.jobs.get(job_id)
async def get_owned(self, job_id: UUID, *, workspace_id: UUID | None) -> Job | None:
self.scopes.append(workspace_id)
job = self.jobs.get(job_id)
if job is None or (workspace_id is not None and job.workspace_id != workspace_id):
return None
return job
async def list_attempts(self, job_id: UUID) -> tuple[JobAttempt, ...]:
started = datetime(2026, 8, 20, 9, 0, tzinfo=UTC)
return (
JobAttempt(
attempt_number=1,
worker_id="worker-1",
status="retry_wait",
leased_at=started,
heartbeat_at=started,
finished_at=started + timedelta(seconds=12),
error_code="retryable_error",
),
)
async def requeue(
self, job_id: UUID, *, workspace_id: UUID | None, now: datetime
) -> Job | None:
self.scopes.append(workspace_id)
if self.fail_requeue_race:
return None
job = self.jobs.get(job_id)
if job is None or job.status is not JobStatus.TERMINAL:
return None
if workspace_id is not None and job.workspace_id != workspace_id:
return None
self.requeued.append(job_id)
return job
def _client(
principal: Principal | None = None,
*,
registry: object | None = None,
document_repository: object | None = None,
) -> tuple[TestClient, FakeJobRepository, FakeControl]:
app = create_app()
control = FakeControl()
jobs = FakeJobRepository()
app.dependency_overrides[get_principal] = lambda: principal or _principal()
app.dependency_overrides[get_control_application] = lambda: control
app.dependency_overrides[get_source_registry] = lambda: registry or FakeRegistry()
app.state.job_repository = jobs
app.state.document_repository = document_repository or control
app.state.session_factory = None # no real DB: audit/source-name lookups must degrade quietly
return TestClient(app), jobs, control
def test_documents_list_shows_state_source_and_filters() -> None:
client, _, control = _client()
response = client.get("/admin/documents")
assert response.status_code == 200
body = response.text
assert "Backup runbook" in body and "Broken scan" in body
assert "Infra runbooks" in body # source name, not a UUID
assert "Runbooks space" in body
assert "Searchable" in body and "Failed" in body
assert "security_quarantined" in body
assert f'href="/admin/sources/{SOURCE_ID}"' in body
assert 'data-operations-journey="source-to-search"' in body
assert 'data-mobile-records="documents"' in body
assert 'data-status-tone="ok"' in body and 'status-badge__icon' in body
failed_only = client.get("/admin/documents?state=failed")
assert "Broken scan" in failed_only.text and "Backup runbook" not in failed_only.text
assert client.get(f"/admin/documents/{control.document.id}").status_code == 200
def test_document_pagination_preserves_the_source_and_state_filters() -> None:
client, _, _ = _client()
response = client.get(
f"/admin/documents?source_id={SOURCE_ID}&state=published&limit=1"
)
assert response.status_code == 200
assert (
f"source_id={SOURCE_ID}&amp;state=published&amp;offset=1&amp;limit=1"
in response.text
)
assert "Filtered to Infra runbooks" in response.text
def test_filtered_document_empty_state_does_not_suggest_initial_setup() -> None:
client, _, _ = _client()
response = client.get("/admin/documents?q=no-such-document")
assert response.status_code == 200
assert "No documents match these filters" in response.text
assert "Clear filters" in response.text
assert "Upload a document into a knowledge space" not in response.text
def test_document_detail_shows_chunks_provenance_versions_and_jobs() -> None:
client, _, control = _client()
response = client.get(f"/admin/documents/{control.document.id}")
assert response.status_code == 200
body = response.text
assert "Run the nightly snapshot SNAP-22" in body
assert "Nightly snapshot" in body and "lines 12" in body
assert "doc/section[1]/p[2]" in body
assert "3fc821a9bd" in body # source revision
assert "text/markdown" in body and "trusted_internal" in body
assert f'href="/admin/jobs/{JOB_ID}"' in body
assert "Infra runbooks" in body
def test_failed_document_detail_explains_failure_and_links_job() -> None:
client, _, control = _client()
response = client.get(f"/admin/documents/{control.failed_document.id}")
assert response.status_code == 200
assert 'role="alert"' in response.text
assert "security gate quarantined" in response.text
assert "not retryable" in response.text
assert "failed before any chunk" in response.text
def test_unknown_document_is_404() -> None:
client, _, _ = _client()
response = client.get(f"/admin/documents/{uuid4()}")
assert response.status_code == 404
assert "Document not found" in response.text
def test_jobs_list_and_detail_show_real_fields_and_retry_for_retryable_terminal_jobs() -> None:
client, jobs, control = _client()
listing = client.get("/admin/jobs")
assert listing.status_code == 200
assert "Ingest document" in listing.text
assert "backup.md" in listing.text
assert "embedding_failed" in listing.text
detail = client.get(f"/admin/jobs/{JOB_ID}")
assert detail.status_code == 200
assert "worker-1" in detail.text
assert "Retry" in detail.text
assert "12.0 s" in detail.text
assert f'href="/admin/documents/{control.document.id}"' in detail.text
assert 'data-operations-journey="source-to-search"' in detail.text
retried = client.post(f"/admin/jobs/{JOB_ID}/retry", follow_redirects=False)
assert retried.status_code == 303
assert jobs.requeued == [JOB_ID]
def test_job_detail_never_links_a_document_from_another_workspace() -> None:
foreign_document = DocumentRecord(
id=uuid4(),
workspace_id=uuid4(),
space_id=SPACE_ID,
source_key=str(SOURCE_ID),
external_id="runbooks/backup.md",
title="Foreign runbook",
source_id=SOURCE_ID,
)
class ForeignDocumentRepository:
async def get_document_by_source(
self, workspace_id: UUID, source_key: str, external_id: str
) -> DocumentRecord | None:
return foreign_document
client, _, _ = _client(document_repository=ForeignDocumentRepository())
response = client.get(f"/admin/jobs/{JOB_ID}")
assert response.status_code == 200
assert f'/admin/documents/{foreign_document.id}' not in response.text
def test_job_links_are_suppressed_when_the_target_route_is_not_authorized() -> None:
auditor, _, control = _client(_principal(Role.AUDITOR))
auditor_list = auditor.get("/admin/jobs")
auditor_detail = auditor.get(f"/admin/jobs/{JOB_ID}")
assert auditor_list.status_code == 200
assert '<span title="Sources"' in auditor_list.text
assert '<span title="Documents"' in auditor_list.text
assert auditor_detail.status_code == 200
assert f'href="/admin/sources/{SOURCE_ID}"' not in auditor_detail.text
assert f'href="/admin/documents/{control.document.id}"' not in auditor_detail.text
assert "Document unavailable" in auditor_detail.text
foreign_workspace = uuid4()
platform = Principal(
uuid4(), foreign_workspace, PrincipalType.HUMAN, frozenset({Role.PLATFORM_ADMIN})
)
platform_client, _, _ = _client(platform)
platform_detail = platform_client.get(f"/admin/jobs/{JOB_ID}")
assert platform_detail.status_code == 200
assert f'href="/admin/sources/{SOURCE_ID}"' not in platform_detail.text
assert f'href="/admin/documents/{control.document.id}"' not in platform_detail.text
def test_document_links_are_suppressed_when_related_resources_are_unavailable() -> None:
viewer, _, control = _client(_principal(Role.VIEWER))
listing = viewer.get("/admin/documents")
detail = viewer.get(f"/admin/documents/{control.document.id}")
failed = viewer.get(f"/admin/documents/{control.failed_document.id}")
assert listing.status_code == 200
assert '<span title="Sources"' in listing.text
assert '<span title="Processing"' in listing.text
assert f'href="/admin/sources/{SOURCE_ID}"' not in listing.text
assert detail.status_code == 200
assert f'href="/admin/sources/{SOURCE_ID}"' not in detail.text
assert f'href="/admin/jobs/{JOB_ID}"' not in detail.text
assert "Source unavailable" in detail.text
assert failed.status_code == 200
assert f'href="/admin/jobs/{control.failed_version.job_id}"' not in failed.text
assert "Job: <span" in failed.text
def test_retry_reports_a_concurrent_state_change_instead_of_claiming_success() -> None:
client, jobs, _ = _client()
jobs.fail_requeue_race = True
response = client.post(f"/admin/jobs/{JOB_ID}/retry", follow_redirects=False)
assert response.status_code == 409
assert "changed before it could be requeued" in response.text
assert "notice=retried" not in response.text
assert jobs.requeued == []
def test_operational_tables_have_an_intentional_compact_mobile_contract() -> None:
client, _, _ = _client()
jobs = client.get("/admin/jobs")
styles = client.get("/static/admin.css")
assert 'data-mobile-records="jobs"' in jobs.text
assert 'data-label="Status"' in jobs.text
assert "[data-mobile-records]" in styles.text
assert "content: attr(data-label)" in styles.text
assert "min-height: 2.75rem" in styles.text
def test_auditor_sees_jobs_but_cannot_retry_and_viewer_is_forbidden() -> None:
client, jobs, _ = _client(_principal(Role.AUDITOR))
assert client.get("/admin/jobs").status_code == 200
detail = client.get(f"/admin/jobs/{JOB_ID}")
assert detail.status_code == 200
assert 'action="/admin/jobs/' not in detail.text
assert client.post(f"/admin/jobs/{JOB_ID}/retry").status_code == 403
assert jobs.requeued == []
viewer, _, _ = _client(_principal(Role.VIEWER))
assert viewer.get("/admin/jobs").status_code == 403
assert viewer.get("/admin/system").status_code == 403
def test_system_page_renders_runtime_facts() -> None:
client, _, _ = _client()
response = client.get("/admin/system")
assert response.status_code == 200
assert "System Health" in response.text
assert "RAGCore version" in response.text
assert "Ingestion queue" in response.text
+124
View File
@@ -0,0 +1,124 @@
"""'/' root redirect and the '/login' landing page."""
from __future__ import annotations
from uuid import uuid4
from fastapi.testclient import TestClient
from ragcore.application.auth import SessionService, SignedTokenCodec
from ragcore.application.auth.ports import AuthorizationChallenge
from ragcore.domain.auth import OidcClaims
from ragcore.domain.control import Role
from ragcore.main import create_app
from ragcore.web.auth.dependencies import get_session_codec, get_session_service
SECRET = b"0" * 32
class FakeOidcProvider:
def __init__(self, claims: OidcClaims) -> None:
self.claims = claims
async def build_authorization_challenge(self, *, redirect_uri: str) -> AuthorizationChallenge:
return AuthorizationChallenge(
redirect_url="https://idp.example.test/authorize?mock=1",
state="fixed-state-for-tests",
nonce="fixed-nonce-for-tests",
code_verifier="fixed-verifier-for-tests",
)
async def complete_login(
self, *, code: str, code_verifier: str, nonce: str, redirect_uri: str
) -> OidcClaims:
return self.claims
def _signed_in_client() -> TestClient:
provider = FakeOidcProvider(
OidcClaims(subject="alice", email="alice@example.test", groups=("ragcore-editors",))
)
service = SessionService(
provider=provider, group_roles={"ragcore-editors": Role.EDITOR}, workspace_id=uuid4()
)
codec = SignedTokenCodec(secret=SECRET)
app = create_app()
app.dependency_overrides[get_session_service] = lambda: service
app.dependency_overrides[get_session_codec] = lambda: codec
# SessionAuthenticationMiddleware reads the codec straight off app.state
# (it runs outside FastAPI's dependency-injection system), so the
# dependency override above -- which only affects the /auth/* routes --
# is not enough to make it recognize the cookie those routes just set.
app.state.auth_session_codec = codec
client = TestClient(app, follow_redirects=False)
client.get("/auth/login")
client.get("/auth/callback", params={"code": "auth-code", "state": "fixed-state-for-tests"})
return client
def test_root_redirects_unauthenticated_visitors_to_login() -> None:
client = TestClient(create_app(), follow_redirects=False)
response = client.get("/")
assert response.status_code == 302
assert response.headers["location"] == "/login"
def test_root_redirects_authenticated_visitors_to_dashboard() -> None:
client = _signed_in_client()
response = client.get("/")
assert response.status_code == 302
assert response.headers["location"] == "/admin/dashboard"
def test_login_page_shows_not_configured_when_oidc_is_absent() -> None:
client = TestClient(create_app(), follow_redirects=False)
response = client.get("/login")
assert response.status_code == 200
assert "No identity provider is configured" in response.text
assert "Sign in with SSO" not in response.text
assert "OIDC secured" not in response.text
assert "Setup required" in response.text
def test_login_page_offers_sso_when_oidc_is_configured() -> None:
app = create_app()
app.state.session_service = object()
client = TestClient(app, follow_redirects=False)
response = client.get("/login")
assert response.status_code == 200
assert "Sign in with SSO" in response.text
assert 'href="/auth/login"' in response.text
def test_login_page_introduces_the_real_ragcore_value_flow() -> None:
app = create_app()
app.state.session_service = object()
response = TestClient(app, follow_redirects=False).get("/login")
assert response.status_code == 200
assert 'data-auth-stage="ragcore"' in response.text
assert "Private knowledge. Verifiable answers." in response.text
assert 'data-rag-flow="sources-retrieval-answers"' in response.text
assert "Dense + sparse" in response.text
assert "Cited answers" in response.text
assert 'aria-describedby="sign-in-description"' in response.text
assert "https://" not in response.text
def test_login_page_declares_a_loadable_local_favicon() -> None:
client = TestClient(create_app(), follow_redirects=False)
response = client.get("/login")
favicon = client.get("/static/favicon.svg")
assert response.status_code == 200
assert '<link rel="icon" href="/static/favicon.svg" type="image/svg+xml">' in response.text
assert favicon.status_code == 200
assert favicon.headers["content-type"].startswith("image/svg+xml")
def test_login_page_redirects_an_already_authenticated_visitor() -> None:
client = _signed_in_client()
response = client.get("/login")
assert response.status_code == 302
assert response.headers["location"] == "/admin/dashboard"
+146
View File
@@ -0,0 +1,146 @@
"""What the jobs screen asks for, and what its links carry forward.
The repository-level proof that filtering happens in SQL lives in
``tests/integration/jobs/test_job_listing_filters.py``. This is the other
half: that the *route* pushes the operator's filter down instead of narrowing
rows it already fetched, and that navigating a page does not silently drop the
filter the operator is looking at.
"""
from __future__ import annotations
from datetime import UTC, datetime, timedelta
from uuid import UUID, uuid4
from fastapi.testclient import TestClient
from ragcore.api.v1.control.dependencies import get_principal
from ragcore.application.jobs import Job, JobListFilter, JobListPage, JobStatus
from ragcore.domain.authorization import Principal, PrincipalType
from ragcore.domain.control import Role
from ragcore.main import create_app
WORKSPACE = uuid4()
NOW = datetime(2026, 8, 20, 9, 0, tzinfo=UTC)
def _job(index: int, *, status: JobStatus, operation: str) -> Job:
return Job(
id=uuid4(),
workspace_id=WORKSPACE,
job_key=f"job-{index}",
operation=operation,
target_key="blob:abc",
profile_version="upload-v1",
payload={"original_name": f"document-{index}.md"},
status=status,
available_at=NOW - timedelta(minutes=index),
trace_id=f"trace-{index}",
)
class RecordingJobRepository:
"""A store big enough that a page is not the whole result set."""
def __init__(self) -> None:
self.jobs = [
_job(
index,
status=JobStatus.TERMINAL if index % 2 else JobStatus.READY,
operation="sync_source" if index % 3 == 0 else "ingest_upload",
)
for index in range(120)
]
self.filters: list[JobListFilter] = []
async def list_jobs(
self, *, workspace_id: UUID | None, filters: JobListFilter
) -> JobListPage:
self.filters.append(filters)
matching = [
job
for job in self.jobs
if (workspace_id is None or job.workspace_id == workspace_id)
and (filters.status is None or job.status is filters.status)
and (filters.operation is None or job.operation == filters.operation)
]
return JobListPage(
items=tuple(matching[filters.offset : filters.offset + filters.limit]),
total=len(matching),
limit=filters.limit,
offset=filters.offset,
)
async def status_counts(self, *, workspace_id: UUID | None) -> dict[str, int]:
counts: dict[str, int] = {}
for job in self.jobs:
counts[job.status.value] = counts.get(job.status.value, 0) + 1
return counts
async def get_owned(self, job_id: UUID, *, workspace_id: UUID | None) -> Job | None:
return next((job for job in self.jobs if job.id == job_id), None)
def _client() -> tuple[TestClient, RecordingJobRepository]:
app = create_app()
repository = RecordingJobRepository()
app.dependency_overrides[get_principal] = lambda: Principal(
uuid4(), WORKSPACE, PrincipalType.HUMAN, frozenset({Role.WORKSPACE_ADMIN})
)
app.state.job_repository = repository
app.state.session_factory = None
return TestClient(app), repository
def test_the_filter_reaches_the_query_rather_than_the_rendered_page() -> None:
client, repository = _client()
response = client.get("/admin/jobs?status=terminal&operation=sync_source")
assert response.status_code == 200
applied = repository.filters[-1]
assert applied.status is JobStatus.TERMINAL
assert applied.operation == "sync_source"
# Every rendered row really is a match: nothing was fetched and hidden.
assert "No jobs match" not in response.text
assert 'data-operations-journey="source-to-search"' in response.text
assert 'data-mobile-records="jobs"' in response.text
def test_a_page_beyond_the_first_is_a_different_query_not_a_longer_one() -> None:
client, repository = _client()
response = client.get("/admin/jobs?status=terminal&offset=50&limit=50")
assert response.status_code == 200
applied = repository.filters[-1]
assert (applied.offset, applied.limit) == (50, 50)
assert applied.status is JobStatus.TERMINAL
# Sixty terminal jobs, fifty per page: page two exists and says so.
assert "Showing 51\u201360 of 60" in response.text
def test_pagination_links_keep_the_active_filter() -> None:
client, _ = _client()
response = client.get("/admin/jobs?status=terminal&operation=sync_source&limit=10")
# The "next page" link must carry both filters, or paging silently widens
# the result set the operator is reading. Every separator in that href is
# an escaped entity: a bare "&" in an attribute is invalid HTML, and the
# only reason it survives today is that no browser happens to read
# "&limit" as a character reference.
assert (
"status=terminal&amp;operation=sync_source&amp;offset=10&amp;limit=10" in response.text
)
assert "Showing 1\u201310 of 20" in response.text
def test_an_unusable_filter_value_is_reported_not_silently_dropped() -> None:
client, repository = _client()
response = client.get("/admin/jobs?status=failed")
assert response.status_code == 200
assert repository.filters[-1].status is None
assert "Unrecognised status filter ignored" in response.text
+595
View File
@@ -0,0 +1,595 @@
"""Sources screens: list/detail/form render real registry data, mutations go
through the management service, and unauthorized principals see nothing."""
from __future__ import annotations
from dataclasses import dataclass, field, replace
from datetime import UTC, datetime
from uuid import UUID, uuid4
import pytest
from fastapi.testclient import TestClient
from ragcore.api.v1.control.dependencies import get_principal
from ragcore.application.documents import (
DocumentListFilter,
DocumentListPage,
DocumentRecord,
DocumentStatusRecord,
DocumentVersionState,
)
from ragcore.application.jobs import Job
from ragcore.application.sources import (
SourceItemRecord,
SourceListFilter,
SourceListPage,
SourceOverview,
SourceRecord,
SourceRegistryError,
SourceStatus,
SourceSyncOutcome,
SourceSyncRunRecord,
)
from ragcore.domain.authorization import (
AuthorizationError,
PermissionDenied,
Principal,
PrincipalType,
ResourceNotFound,
)
from ragcore.domain.control import Role
from ragcore.domain.sources import ConnectorKind, SourceSyncState
from ragcore.main import create_app
from ragcore.web.sources import get_source_management
WORKSPACE_ID = uuid4()
SPACE_ID = uuid4()
@dataclass
class FakeSourceManagement:
sources: dict[UUID, SourceRecord] = field(default_factory=dict)
runs: dict[UUID, list[SourceSyncRunRecord]] = field(default_factory=dict)
documents: dict[UUID, list[DocumentRecord]] = field(default_factory=dict)
failed_items: dict[UUID, list[SourceItemRecord]] = field(default_factory=dict)
manage: bool = True
manage_filesystem: bool = True
actions: list[tuple[str, UUID]] = field(default_factory=list)
created: list[dict[str, object]] = field(default_factory=list)
def can_manage(self, principal: Principal) -> bool:
return self.manage
def can_manage_filesystem_sources(self, principal: Principal) -> bool:
return self.manage and self.manage_filesystem
def _check(self) -> None:
if not self.manage:
raise PermissionDenied("no")
async def list_sources(self, principal: Principal, filters: SourceListFilter):
items = [
source
for source in self.sources.values()
if (filters.kind is None or source.kind is filters.kind)
and (filters.search is None or filters.search.lower() in source.name.lower())
and source.status is not SourceStatus.DELETED
]
page = SourceListPage(items=tuple(items), total=len(items), limit=filters.limit, offset=0)
counts = {source.id: len(self.documents.get(source.id, [])) for source in items}
return page, counts, {SPACE_ID: "Runbooks space"}
async def get_source(self, principal: Principal, source_id: UUID) -> SourceOverview:
source = self.sources.get(source_id)
if source is None:
raise ResourceNotFound("source not found")
return SourceOverview(
source=source,
document_count=len(self.documents.get(source_id, [])),
space_name="Runbooks space",
failed_items=tuple(self.failed_items.get(source_id, [])),
)
async def sync_history(self, principal: Principal, source_id: UUID, *, limit: int = 20):
return tuple(self.runs.get(source_id, []))
async def documents_of(
self, principal: Principal, source_id: UUID, filters: DocumentListFilter
):
items = tuple(
DocumentStatusRecord(
document=document,
latest_state=DocumentVersionState.PUBLISHED,
parser_version="text-parser-1",
chunk_profile_version="prose-v1",
updated_at=datetime.now(UTC),
)
for document in self.documents.get(source_id, [])
)
return DocumentListPage(items=items, total=len(items), limit=filters.limit, offset=0)
async def create_source(
self, principal, *, name, kind, space_id, config_values, trace_id,
sync_interval_seconds=None,
):
self._check()
if kind is ConnectorKind.FOLDER and not config_values.get("root", "").startswith("/"):
raise SourceRegistryError("root must be an absolute non-traversing path")
record = SourceRecord(
id=uuid4(),
workspace_id=WORKSPACE_ID,
space_id=space_id,
name=name,
kind=kind,
config={"root": config_values.get("root")},
)
self.sources[record.id] = record
self.created.append(
{
"name": name,
"kind": kind,
"config": dict(config_values),
"sync_interval_seconds": sync_interval_seconds,
}
)
return record
async def update_source(
self, principal, source_id, *, name, config_values, trace_id,
sync_interval_seconds=None,
):
self._check()
self.actions.append(("update", source_id))
self.updated_intervals.append(sync_interval_seconds)
return self.sources[source_id]
async def set_status(self, principal, source_id, status, *, trace_id):
self._check()
if source_id not in self.sources:
raise ResourceNotFound("source not found")
self.actions.append((status.value, source_id))
return self.sources[source_id]
async def request_sync(self, principal, source_id, *, trace_id):
self._check()
source = self.sources.get(source_id)
if source is None:
raise ResourceNotFound("source not found")
if not source.syncable:
raise SourceRegistryError("this source kind is fed by its callers, not synced")
self.actions.append(("sync", source_id))
return Job(
id=uuid4(),
job_key="k",
operation="sync_source",
target_key=str(source_id),
profile_version="sync-v1",
)
def _principal(role: Role = Role.WORKSPACE_ADMIN) -> Principal:
return Principal(uuid4(), WORKSPACE_ID, PrincipalType.HUMAN, frozenset({role}))
def _fixture(
service: FakeSourceManagement,
principal: Principal | None = None,
*,
resolve_failed_jobs: bool = True,
) -> TestClient:
app = create_app()
app.dependency_overrides[get_principal] = lambda: principal or _principal()
app.dependency_overrides[get_source_management] = lambda: service
class OwnedJobs:
async def get_owned(
self, job_id: UUID, *, workspace_id: UUID | None
) -> Job | None:
known = any(
item.last_failure_job_id == job_id
for items in service.failed_items.values()
for item in items
)
if not resolve_failed_jobs or not known or workspace_id != WORKSPACE_ID:
return None
return Job(
id=job_id,
workspace_id=WORKSPACE_ID,
job_key=f"failed-{job_id}",
operation="ingest_upload",
target_key="failed-item",
profile_version="upload-v1",
)
app.state.job_repository = OwnedJobs()
return TestClient(app)
def _folder_source(name: str = "Infra runbooks") -> SourceRecord:
return SourceRecord(
id=uuid4(),
workspace_id=WORKSPACE_ID,
space_id=SPACE_ID,
name=name,
kind=ConnectorKind.FOLDER,
config={"root": "/mnt/runbooks", "include": ["*.md"], "trust_level": "trusted_internal"},
last_sync_at=datetime(2026, 8, 20, 10, 0, tzinfo=UTC),
)
def test_sources_list_shows_empty_state_with_action_and_grouped_navigation() -> None:
client = _fixture(FakeSourceManagement())
response = client.get("/admin/sources")
assert response.status_code == 200
assert "No sources configured yet" in response.text
assert 'href="/admin/sources/new"' in response.text
# The grouped information architecture is rendered for every screen.
for label in ("Knowledge", "Access", "Quality", "Operations", "Sources", "Documents"):
assert label in response.text
assert 'aria-current="page"' in response.text
def test_sources_list_renders_registry_rows_with_counts_and_filters() -> None:
service = FakeSourceManagement()
source = _folder_source()
service.sources[source.id] = source
service.documents[source.id] = [
DocumentRecord(
uuid4(), WORKSPACE_ID, SPACE_ID, str(source.id), "a.md", "A", source_id=source.id
)
]
client = _fixture(service)
response = client.get("/admin/sources?q=infra&kind=folder")
assert response.status_code == 200
assert "Infra runbooks" in response.text
assert "Runbooks space" in response.text
assert "2026-08-20 10:00" in response.text
assert f'href="/admin/sources/{source.id}"' in response.text
assert f'href="/admin/documents?source_id={source.id}"' in response.text
assert 'role="search"' in response.text
assert 'data-operations-journey="source-to-search"' in response.text
assert 'data-mobile-records="sources"' in response.text
def test_invalid_source_filter_is_reported_without_dropping_valid_filters() -> None:
service = FakeSourceManagement()
matching = _folder_source("Infra runbooks")
unrelated = _folder_source("Employee handbook")
service.sources[matching.id] = matching
service.sources[unrelated.id] = unrelated
response = _fixture(service).get("/admin/sources?q=infra&kind=not-a-kind")
assert response.status_code == 200
assert "Infra runbooks" in response.text
assert "Employee handbook" not in response.text
assert "Unrecognised type filter ignored" in response.text
assert 'value="infra"' in response.text
assert 'value="not-a-kind"' not in response.text
def test_filtered_source_empty_state_does_not_claim_the_registry_is_empty() -> None:
service = FakeSourceManagement()
source = _folder_source()
service.sources[source.id] = source
response = _fixture(service).get("/admin/sources?q=no-such-source")
assert response.status_code == 200
assert "No sources match these filters" in response.text
assert "No sources configured yet" not in response.text
assert 'href="/admin/sources"' in response.text
def test_source_detail_shows_configuration_documents_and_sync_history() -> None:
service = FakeSourceManagement()
source = _folder_source()
service.sources[source.id] = source
service.runs[source.id] = [
SourceSyncRunRecord(
id=uuid4(),
source_id=source.id,
started_at=datetime(2026, 8, 20, 10, 0, tzinfo=UTC),
finished_at=datetime(2026, 8, 20, 10, 1, tzinfo=UTC),
outcome=SourceSyncOutcome.COMPLETED,
discovered=12,
new=3,
changed=1,
unchanged=8,
removed=0,
)
]
service.documents[source.id] = [
DocumentRecord(
uuid4(),
WORKSPACE_ID,
SPACE_ID,
str(source.id),
"runbooks/backup.md",
"Backup",
source_id=source.id,
)
]
client = _fixture(service)
response = client.get(f"/admin/sources/{source.id}")
assert response.status_code == 200
body = response.text
assert "/mnt/runbooks" in body
assert "12 discovered" in body and "3 new" in body
assert "runbooks/backup.md" in body
assert "Sync now" in body
assert "data-confirm" in body # destructive actions confirm
assert 'action="/admin/sources/' + str(source.id) + '/delete"' in body
@pytest.mark.parametrize(
("outcome", "failed", "expected"),
[
(SourceSyncOutcome.RUNNING, 0, "Syncing"),
(SourceSyncOutcome.AWAITING_INGEST, 0, "Indexing child jobs"),
(SourceSyncOutcome.COMPLETED_WITH_FAILURES, 1, "Completed with failures"),
],
)
def test_source_sync_history_names_unfinished_and_incomplete_outcomes_truthfully(
outcome: SourceSyncOutcome, failed: int, expected: str
) -> None:
service = FakeSourceManagement()
source = _folder_source()
service.sources[source.id] = source
service.runs[source.id] = [
SourceSyncRunRecord(
id=uuid4(),
source_id=source.id,
started_at=datetime(2026, 8, 20, 10, 0, tzinfo=UTC),
finished_at=datetime(2026, 8, 20, 10, 1, tzinfo=UTC),
outcome=outcome,
discovered=3,
new=1,
changed=0,
unchanged=2,
removed=0,
failed=failed,
)
]
response = _fixture(service).get(f"/admin/sources/{source.id}")
assert response.status_code == 200
assert expected in response.text
def test_unknown_source_is_a_404_with_reference() -> None:
client = _fixture(FakeSourceManagement())
response = client.get(f"/admin/sources/{uuid4()}")
assert response.status_code == 404
assert "Source not found" in response.text
assert "Reference:" in response.text
def test_create_source_validates_and_redirects_to_detail() -> None:
service = FakeSourceManagement()
client = _fixture(service)
invalid = client.post(
"/admin/sources",
data={"name": "Bad", "kind": "folder", "space_id": str(SPACE_ID), "root": "relative/path"},
)
assert invalid.status_code == 400
assert "absolute" in invalid.text
assert 'role="alert"' in invalid.text
created = client.post(
"/admin/sources",
data={
"name": "Infra runbooks",
"kind": "folder",
"space_id": str(SPACE_ID),
"root": "/mnt/runbooks",
"include": "*.md",
"trust_level": "trusted_internal",
},
follow_redirects=False,
)
assert created.status_code == 303
assert created.headers["location"].startswith("/admin/sources/")
assert service.created[0]["name"] == "Infra runbooks"
detail = client.get(created.headers["location"])
assert detail.status_code == 200
assert "Source created." in detail.text
def test_actions_call_the_service_and_upload_sources_cannot_sync() -> None:
service = FakeSourceManagement()
folder = _folder_source()
upload = SourceRecord(
id=uuid4(),
workspace_id=WORKSPACE_ID,
space_id=SPACE_ID,
name="Uploads",
kind=ConnectorKind.UPLOAD,
)
service.sources[folder.id] = folder
service.sources[upload.id] = upload
client = _fixture(service)
sync = client.post(f"/admin/sources/{folder.id}/sync", follow_redirects=False)
assert sync.status_code == 303 and "notice=sync_requested" in sync.headers["location"]
pause = client.post(f"/admin/sources/{folder.id}/pause", follow_redirects=False)
assert pause.status_code == 303
delete = client.post(f"/admin/sources/{folder.id}/delete", follow_redirects=False)
assert (
delete.status_code == 303 and delete.headers["location"] == "/admin/sources?notice=deleted"
)
assert [action for action, _ in service.actions] == ["sync", "paused", "deleted"]
refused = client.post(f"/admin/sources/{upload.id}/sync")
assert refused.status_code == 409
assert "fed by its callers" in refused.text
# Upload sources show no Sync button and no delete.
page = client.get(f"/admin/sources/{upload.id}")
assert "Sync now" not in page.text
def test_viewer_cannot_see_the_form_or_mutate_and_leaks_nothing() -> None:
service = FakeSourceManagement(manage=False)
source = _folder_source("Secret source")
service.sources[source.id] = source
client = _fixture(service, _principal(Role.VIEWER))
form = client.get("/admin/sources/new")
assert form.status_code == 403
assert "Secret source" not in form.text
mutate = client.post(f"/admin/sources/{source.id}/sync")
assert mutate.status_code == 403
listing = client.get("/admin/sources")
assert listing.status_code == 200
assert 'href="/admin/sources/new"' not in listing.text
def test_authorization_errors_render_forbidden_state() -> None:
class Denying(FakeSourceManagement):
async def list_sources(self, principal, filters):
raise AuthorizationError("denied")
client = _fixture(Denying())
response = client.get("/admin/sources")
assert response.status_code == 403
assert "Access denied" in response.text
# -- the Control Plane must not render "nothing to see" for unfinished work --
@pytest.mark.parametrize(
("state", "expected"),
[
(SourceSyncState.AWAITING_INGEST, "Indexing"),
(SourceSyncState.COMPLETED_WITH_FAILURES, "Last sync incomplete"),
(SourceSyncState.COMPLETED, "Last sync ok"),
(SourceSyncState.FAILED, "Last sync failed"),
(SourceSyncState.SCANNING, "Syncing"),
],
)
def test_every_sync_state_renders_a_badge_on_both_screens(
state: SourceSyncState, expected: str
) -> None:
"""A state with no badge shows as an unqualified "Active" source, which an
operator reads as finished -- exactly the lie convergence removes."""
service = FakeSourceManagement()
source = replace(_folder_source(), sync_state=state)
service.sources[source.id] = source
client = _fixture(service)
assert expected in client.get("/admin/sources").text
assert expected in client.get(f"/admin/sources/{source.id}").text
def test_an_unconverged_item_says_what_to_retry_instead_of_hiding() -> None:
"""A terminally failed item whose content has not changed is deliberately
never re-enqueued by the next sync, so the screen has to name the recovery
path. Reporting only discovery counts would leave it reading as
"unchanged" forever while nothing was ever indexed."""
service = FakeSourceManagement()
source = _folder_source()
service.sources[source.id] = source
failed_job_id = uuid4()
service.failed_items[source.id] = [
SourceItemRecord(
source_id=source.id,
external_id="runbooks/broken.pdf",
fingerprint="a" * 64,
locator="/mnt/rag-sources/runbooks/broken.pdf",
last_seen_at=datetime(2026, 8, 20, 10, 0, tzinfo=UTC),
last_failure_code="embedding_failed",
last_failure_retryable=True,
last_failure_job_id=failed_job_id,
)
]
client = _fixture(service)
response = client.get(f"/admin/sources/{source.id}")
assert response.status_code == 200
body = response.text
assert "Ingest failed" in body
assert "runbooks/broken.pdf" in body
assert "embedding_failed" in body
assert "retry the failed ingest job" in body
assert f'href="/admin/jobs/{failed_job_id}"' in body
def test_failed_source_item_does_not_link_an_unreachable_recorded_job() -> None:
service = FakeSourceManagement()
source = _folder_source()
failed_job_id = uuid4()
service.sources[source.id] = source
service.failed_items[source.id] = [
SourceItemRecord(
source_id=source.id,
external_id="runbooks/missing.pdf",
fingerprint="b" * 64,
locator="/mnt/rag-sources/runbooks/missing.pdf",
last_seen_at=datetime(2026, 8, 20, 10, 0, tzinfo=UTC),
last_failure_code="parse_failed",
last_failure_retryable=True,
last_failure_job_id=failed_job_id,
)
]
response = _fixture(service, resolve_failed_jobs=False).get(
f"/admin/sources/{source.id}"
)
assert response.status_code == 200
assert f'href="/admin/jobs/{failed_job_id}"' not in response.text
assert "recorded job is unavailable" in response.text
def test_a_sync_interval_can_be_set_on_the_form_and_is_bounded() -> None:
"""Automatic syncing is opt-in per source, and the form is where an
operator opts in. Leaving it blank has to keep meaning "only when I ask"
-- that is the behaviour every source had before there was a scheduler."""
service = FakeSourceManagement()
client = _fixture(service)
without = client.post(
"/admin/sources",
data={
"name": "Manual only",
"kind": "folder",
"space_id": str(SPACE_ID),
"root": "/mnt/runbooks",
"sync_interval_minutes": "",
},
follow_redirects=False,
)
assert without.status_code == 303
assert service.created[-1]["sync_interval_seconds"] is None
scheduled = client.post(
"/admin/sources",
data={
"name": "Hourly",
"kind": "folder",
"space_id": str(SPACE_ID),
"root": "/mnt/runbooks",
"sync_interval_minutes": "60",
},
follow_redirects=False,
)
assert scheduled.status_code == 303
assert service.created[-1]["sync_interval_seconds"] == 3600
# One minute would spend the worker rediscovering unchanged content.
too_often = client.post(
"/admin/sources",
data={
"name": "Too often",
"kind": "folder",
"space_id": str(SPACE_ID),
"root": "/mnt/runbooks",
"sync_interval_minutes": "1",
},
)
assert too_often.status_code == 400
assert 'role="alert"' in too_often.text