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,131 @@
"""M6-07: document the intentional citation-immutability boundary.
`docs/05_RETRIEVAL/CITATIONS.md` is explicit: a citation is immutable, and
resolving one "re-authorizes and returns only content the caller may
currently read" -- scoped to workspace/space membership. It does not say
document/version lifecycle state revokes a citation, and
`test_citations.py::test_citation_survives_document_supersession_and_creation_is_idempotent`
already proves supersession doesn't either. `CitationService.resolve()`
and `PostgresCitationRepository.get_authorized()` both confirm this by
construction: neither joins against `documents`/`document_versions` at
all, only `citations.workspace_id`/`citations.space_id`.
This test locks that boundary in explicitly for M6-07 (rather than leaving
it merely implied by what other tests happen not to check), and proves the
control that *does* apply -- deactivating the knowledge space the citation
belongs to -- correctly revokes access, since `effective_space_ids` is
recomputed fresh on every request from the space's current active state.
"""
from __future__ import annotations
from datetime import UTC, datetime
from uuid import UUID, uuid4
import pytest
from ragcore.application.citations import CitationService
from ragcore.application.retrieval.authorization import AuthorizedRetrievalScope
from ragcore.domain.authorization import Principal, PrincipalType, ResourceNotFound
from ragcore.domain.citations import Citation
from ragcore.domain.control import Role
class InMemoryCitationRepository:
"""Mirrors PostgresCitationRepository.get_authorized exactly: workspace
and space membership only, no join against document/version state."""
def __init__(self) -> None:
self.rows: dict[object, Citation] = {}
async def create(self, value: Citation) -> Citation:
self.rows.setdefault(value.id, value)
return self.rows[value.id]
async def get_authorized(
self, citation_id: UUID, *, workspace_id: UUID, effective_space_ids: frozenset[UUID]
) -> Citation | None:
value = self.rows.get(citation_id)
if (
value is None
or value.workspace_id != workspace_id
or value.space_id not in effective_space_ids
):
return None
return value
def _citation(*, workspace_id: UUID, space_id: UUID, document_id: UUID) -> Citation:
return Citation.create(
workspace_id=workspace_id,
space_id=space_id,
document_id=document_id,
document_version_id=uuid4(),
chunk_id=uuid4(),
parent_chunk_id=None,
location={"page": 1},
excerpt="A cited excerpt from a document that will later be deleted.",
source_uri="https://example.test/doc.md",
acquired_at=datetime(2026, 8, 1, 12, 0, tzinfo=UTC),
retrieval_run_id=uuid4(),
index_alias="rag_dense_hybrid_active",
profile_version="hybrid-v1",
)
def _principal(workspace_id: UUID) -> Principal:
return Principal(
id=uuid4(), workspace_id=workspace_id, principal_type=PrincipalType.HUMAN,
roles=frozenset({Role.VIEWER}),
)
@pytest.mark.security
@pytest.mark.asyncio
async def test_citation_to_a_deleted_document_remains_resolvable_by_deliberate_design() -> None:
"""Intentional (see docs/05_RETRIEVAL/CITATIONS.md): a citation is an
immutable historical record, re-authorized by workspace/space on every
read -- not revoked because the source document was later deleted."""
workspace_id, space_id, document_id = uuid4(), uuid4(), uuid4()
repository = InMemoryCitationRepository()
service = CitationService(repository)
scope = AuthorizedRetrievalScope(workspace_id, frozenset({space_id}))
created = await service.create(
_principal(workspace_id), scope, _citation(
workspace_id=workspace_id, space_id=space_id, document_id=document_id
)
)
# The document is now deleted; the repository has no notion of that at
# all (it never stored a document/version reference to check), which is
# exactly the point -- the citation's own excerpt is self-contained.
resolved = await service.resolve(_principal(workspace_id), scope, created.id)
assert resolved.id == created.id
assert resolved.excerpt == created.excerpt
@pytest.mark.security
@pytest.mark.asyncio
async def test_citation_becomes_unresolvable_once_its_space_is_no_longer_in_scope() -> None:
"""The control that DOES apply: effective_space_ids is recomputed fresh
per request from the space's current grant/active state, so deactivating
or revoking access to a space immediately revokes its citations too."""
workspace_id, space_id, document_id = uuid4(), uuid4(), uuid4()
repository = InMemoryCitationRepository()
service = CitationService(repository)
scope_with_access = AuthorizedRetrievalScope(workspace_id, frozenset({space_id}))
created = await service.create(
_principal(workspace_id), scope_with_access, _citation(
workspace_id=workspace_id, space_id=space_id, document_id=document_id
)
)
# A later request where the space is no longer in the caller's
# effective scope (deactivated, or the grant was revoked).
scope_without_access = AuthorizedRetrievalScope(workspace_id, frozenset())
with pytest.raises(ResourceNotFound):
await service.resolve(_principal(workspace_id), scope_without_access, created.id)
+172
View File
@@ -0,0 +1,172 @@
from __future__ import annotations
from datetime import UTC, datetime
from uuid import uuid4
import pytest
from ragcore.application.citations import CitationService
from ragcore.application.retrieval.authorization import AuthorizedRetrievalScope
from ragcore.domain.authorization import Principal, PrincipalType, ResourceNotFound
from ragcore.domain.citations import Citation
from ragcore.domain.control import Role
def citation(*, workspace_id, space_id, version_id=None) -> Citation:
return Citation.create(
workspace_id=workspace_id,
space_id=space_id,
document_id=uuid4(),
document_version_id=version_id or uuid4(),
chunk_id=uuid4(),
parent_chunk_id=None,
location={"page": 3, "line_start": 10, "line_end": 14},
excerpt="A stable cited excerpt.",
source_uri="https://example.test/runbook.md",
acquired_at=datetime(2026, 8, 1, 12, 0, tzinfo=UTC),
retrieval_run_id=uuid4(),
index_alias="rag_dense_hybrid_active",
profile_version="hybrid-v1",
)
class InMemoryCitationRepository:
def __init__(self) -> None:
self.rows: dict[object, Citation] = {}
async def create(self, value: Citation) -> Citation:
self.rows.setdefault(value.id, value)
return self.rows[value.id]
async def get_authorized(
self,
citation_id,
*,
workspace_id,
effective_space_ids,
) -> Citation | None:
value = self.rows.get(citation_id)
if (
value is None
or value.workspace_id != workspace_id
or value.space_id not in effective_space_ids
):
return None
return value
def principal(workspace_id) -> Principal:
return Principal(
id=uuid4(),
workspace_id=workspace_id,
principal_type=PrincipalType.HUMAN,
roles=frozenset({Role.VIEWER}),
)
@pytest.mark.asyncio
async def test_citation_survives_document_supersession_and_creation_is_idempotent() -> None:
workspace_id = uuid4()
space_id = uuid4()
scope = AuthorizedRetrievalScope(workspace_id, frozenset({space_id}))
repository = InMemoryCitationRepository()
service = CitationService(repository)
first = citation(workspace_id=workspace_id, space_id=space_id)
stored_first = await service.create(principal(workspace_id), scope, first)
stored_again = await service.create(principal(workspace_id), scope, first)
superseding = citation(
workspace_id=workspace_id,
space_id=space_id,
version_id=uuid4(),
)
await service.create(principal(workspace_id), scope, superseding)
resolved = await service.resolve(principal(workspace_id), scope, first.id)
assert stored_first == stored_again == first
assert resolved == first
assert len(repository.rows) == 2
@pytest.mark.asyncio
async def test_guessed_or_forbidden_citation_ids_are_hidden() -> None:
workspace_id = uuid4()
allowed_space = uuid4()
forbidden_space = uuid4()
scope = AuthorizedRetrievalScope(workspace_id, frozenset({allowed_space}))
repository = InMemoryCitationRepository()
service = CitationService(repository)
allowed_principal = principal(workspace_id)
forbidden = citation(workspace_id=workspace_id, space_id=forbidden_space)
repository.rows[forbidden.id] = forbidden
with pytest.raises(ResourceNotFound):
await service.resolve(allowed_principal, scope, forbidden.id)
with pytest.raises(ResourceNotFound):
await service.resolve(allowed_principal, scope, uuid4())
with pytest.raises(ResourceNotFound):
await service.create(allowed_principal, scope, forbidden)
def test_excerpt_checksum_and_location_are_stable_and_tampering_fails() -> None:
workspace_id = uuid4()
space_id = uuid4()
inputs = {
"workspace_id": workspace_id,
"space_id": space_id,
"document_id": uuid4(),
"document_version_id": uuid4(),
"chunk_id": uuid4(),
"parent_chunk_id": None,
"location": {"line_end": 14, "line_start": 10, "page": 3},
"excerpt": "A stable cited excerpt.",
"source_uri": "https://example.test/runbook.md",
"acquired_at": datetime(2026, 8, 1, 12, 0, tzinfo=UTC),
"retrieval_run_id": uuid4(),
"index_alias": "rag_dense_hybrid_active",
"profile_version": "hybrid-v1",
}
first = Citation.create(**inputs)
second = Citation.create(**inputs)
assert first.id == second.id
assert first.excerpt_checksum == second.excerpt_checksum
assert list(first.location) == ["line_end", "line_start", "page"]
with pytest.raises(ValueError, match="checksum"):
Citation(
**{
**inputs,
"id": first.id,
"excerpt_checksum": "0" * 64,
}
)
def test_location_and_identity_cannot_be_forged_after_creation() -> None:
workspace_id = uuid4()
space_id = uuid4()
value = citation(workspace_id=workspace_id, space_id=space_id)
with pytest.raises(TypeError):
value.location["page"] = 99 # type: ignore[index]
with pytest.raises(ValueError, match="id does not match"):
Citation(
**{
"id": uuid4(),
"workspace_id": value.workspace_id,
"space_id": value.space_id,
"document_id": value.document_id,
"document_version_id": value.document_version_id,
"chunk_id": value.chunk_id,
"parent_chunk_id": value.parent_chunk_id,
"location": dict(value.location),
"excerpt": value.excerpt,
"excerpt_checksum": value.excerpt_checksum,
"source_uri": value.source_uri,
"acquired_at": value.acquired_at,
"retrieval_run_id": value.retrieval_run_id,
"index_alias": value.index_alias,
"profile_version": value.profile_version,
}
)