From 73944f91ea3ba51898928f06b5b587df3b3e3add Mon Sep 17 00:00:00 2001 From: Yiorgis Gozadinos Date: Wed, 19 Aug 2026 13:14:21 +0300 Subject: [PATCH] Close the source adapter one-shot ingestion builds create_document_from_source resolves a fetcher per call and never closed it, so every one-shot URL or WebDAV ingest leaked an httpx connection pool. Close it, but only when we built it: resolve_adhoc_fetcher returns a caller-supplied source when one matches the URI, and the ingester keeps those open across jobs. Directory ingestion also yielded symlinked files resolving outside the directory it was given. rglob does not recurse into symlinked directories, so a symlinked file was the only way out of the tree; skip those, as FSSource.discover already does. The chunk repository docstring named client._ensure_chunks_embedded, which does not exist. --- CHANGELOG.md | 2 + haiku_rag_slim/haiku/rag/client/documents.py | 143 ++++++++++-------- .../haiku/rag/store/repositories/chunk.py | 3 +- ...t_adhoc_source_is_closed_after_ingest.yaml | 44 ++++++ ...red_source_is_not_closed_after_ingest.yaml | 44 ++++++ ...gest_skips_symlinks_escaping_the_tree.yaml | 82 ++++++++++ tests/test_client.py | 95 ++++++++++++ 7 files changed, 350 insertions(+), 63 deletions(-) create mode 100644 tests/cassettes/test_client/test_adhoc_source_is_closed_after_ingest.yaml create mode 100644 tests/cassettes/test_client/test_configured_source_is_not_closed_after_ingest.yaml create mode 100644 tests/cassettes/test_client/test_directory_ingest_skips_symlinks_escaping_the_tree.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 0731b93b..c65e55ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ ### Fixed +- `create_document_from_source` closes the source adapter it builds for the call; adapters passed in through `sources` are left to their owner. +- Directory ingestion skips symlinked files resolving outside the given directory, matching `FSSource.discover`. - A FULL rebuild no longer deletes a source-backed document before re-ingesting it: it refreshes the document in place, so the document id is preserved and a failed fetch or conversion falls back to rebuilding from stored content instead of losing the document. - `DocumentRepository.delete_all` recreated `document_items` from `DocumentItemRecord` instead of `get_document_items_arrow_schema()`, returning `picture_data` as `binary` rather than `large_binary`. - `server.json` runtime arguments are `mcp --stdio`, was `serve --mcp`. diff --git a/haiku_rag_slim/haiku/rag/client/documents.py b/haiku_rag_slim/haiku/rag/client/documents.py index d3256a69..e3b23df1 100644 --- a/haiku_rag_slim/haiku/rag/client/documents.py +++ b/haiku_rag_slim/haiku/rag/client/documents.py @@ -726,6 +726,14 @@ async def create_document_from_source( documents: list[Document] = [] filter = FileFilter() for child in local_path.rglob("*"): + # rglob does not recurse into symlinked directories, but it does + # yield symlinked files. Skip the ones resolving outside the + # directory the caller named, as FSSource.discover does. + if child.is_symlink(): + resolved = child.resolve(strict=False) + if not resolved.is_relative_to(local_path.resolve()): + continue + child = resolved if child.is_file() and filter.include_file(str(child)): doc = await create_document_from_source( client, @@ -768,80 +776,91 @@ async def create_document_from_source( source_str, sources=sources, storage_options=storage_options ) - # The stored URI is what we look up + persist by. For an explicit uri - # override, use it as-is. For a file:// input the source string is - # already canonical (URL-encoded); round-tripping via Path.as_uri() - # would double-encode any escapes like %5B. For bare paths, canonicalize. - if uri is not None: - stored_uri = uri - elif parsed_url.scheme == "file": - stored_uri = source_str - elif parsed_url.scheme == "": - stored_uri = Path(source_str).absolute().as_uri() - else: - stored_uri = source_str + # A fetcher built for this call holds its own httpx pool (HTTP, WebDAV) and + # has to be closed here. One handed in through `sources` belongs to the + # caller: the ingester keeps its sources open across jobs. + owns_fetcher = all(fetcher is not configured for configured in sources or ()) - existing_doc = await client.get_document_by_uri(stored_uri) + try: + # The stored URI is what we look up + persist by. For an explicit uri + # override, use it as-is. For a file:// input the source string is + # already canonical (URL-encoded); round-tripping via Path.as_uri() + # would double-encode any escapes like %5B. For bare paths, canonicalize. + if uri is not None: + stored_uri = uri + elif parsed_url.scheme == "file": + stored_uri = source_str + elif parsed_url.scheme == "": + stored_uri = Path(source_str).absolute().as_uri() + else: + stored_uri = source_str - # Cheap revision-based short-circuit: only worth a HEAD when we have a - # stored revision to compare against. All sources persist their native - # revision (mtime_ns for FS, ETag for S3, ETag/Last-Modified for HTTP) - # under the canonical "source_revision" metadata key. - stored_revision = ( - (existing_doc.metadata or {}).get("source_revision") if existing_doc else None - ) - if existing_doc and stored_revision and not force: - current_revision = await fetcher.head(source_str) - if current_revision == stored_revision: + existing_doc = await client.get_document_by_uri(stored_uri) + + # Cheap revision-based short-circuit: only worth a HEAD when we have a + # stored revision to compare against. All sources persist their native + # revision (mtime_ns for FS, ETag for S3, ETag/Last-Modified for HTTP) + # under the canonical "source_revision" metadata key. + stored_revision = ( + (existing_doc.metadata or {}).get("source_revision") + if existing_doc + else None + ) + if existing_doc and stored_revision and not force: + current_revision = await fetcher.head(source_str) + if current_revision == stored_revision: + return await _refresh_doc_metadata( + client, + existing_doc, + title=title, + user_metadata=metadata, + source_metadata=None, + ) + + with logfire.span("document.fetch", uri=source_str) as fetch_span: + result = await fetcher.fetch(source_str) + fetch_span.set_attribute("bytes", len(result.body)) + fetch_span.set_attribute("content_hash", result.content_hash) + + provider_metadata = await _provider_metadata( + metadata_provider, source_id or fetcher.source_id, source_str, result + ) + user_metadata = {**metadata, **provider_metadata} + + # MD5 short-circuit: the bytes are unchanged even if the revision wasn't. + # Refresh the source-derived metadata (revision may have rolled) but skip + # convert/embed/store entirely. + if ( + existing_doc + and not force + and existing_doc.metadata.get("md5") == result.content_hash + ): + source_meta: dict = { + "content_type": result.content_type, + "md5": result.content_hash, + **result.extra_metadata, + } + if result.revision is not None: + source_meta["source_revision"] = result.revision return await _refresh_doc_metadata( client, existing_doc, title=title, - user_metadata=metadata, - source_metadata=None, + user_metadata=user_metadata, + source_metadata=source_meta, ) - with logfire.span("document.fetch", uri=source_str) as fetch_span: - result = await fetcher.fetch(source_str) - fetch_span.set_attribute("bytes", len(result.body)) - fetch_span.set_attribute("content_hash", result.content_hash) - - provider_metadata = await _provider_metadata( - metadata_provider, source_id or fetcher.source_id, source_str, result - ) - user_metadata = {**metadata, **provider_metadata} - - # MD5 short-circuit: the bytes are unchanged even if the revision wasn't. - # Refresh the source-derived metadata (revision may have rolled) but skip - # convert/embed/store entirely. - if ( - existing_doc - and not force - and existing_doc.metadata.get("md5") == result.content_hash - ): - source_meta: dict = { - "content_type": result.content_type, - "md5": result.content_hash, - **result.extra_metadata, - } - if result.revision is not None: - source_meta["source_revision"] = result.revision - return await _refresh_doc_metadata( + return await _ingest_fetch_result( client, - existing_doc, + result, title=title, user_metadata=user_metadata, - source_metadata=source_meta, + stored_uri=stored_uri, + existing_doc=existing_doc, ) - - return await _ingest_fetch_result( - client, - result, - title=title, - user_metadata=user_metadata, - stored_uri=stored_uri, - existing_doc=existing_doc, - ) + finally: + if owns_fetcher: + await fetcher.aclose() async def update_document( diff --git a/haiku_rag_slim/haiku/rag/store/repositories/chunk.py b/haiku_rag_slim/haiku/rag/store/repositories/chunk.py index ecfe9f49..d3005128 100644 --- a/haiku_rag_slim/haiku/rag/store/repositories/chunk.py +++ b/haiku_rag_slim/haiku/rag/store/repositories/chunk.py @@ -60,7 +60,8 @@ class ChunkRepository: """Create one or more chunks in the database. Chunks must have embeddings set before calling this method. - Use client._ensure_chunks_embedded() to embed chunks if needed. + Use haiku.rag.client.processing.ensure_chunks_embedded() to embed + chunks if needed. """ self.store._assert_writable() # Handle single chunk diff --git a/tests/cassettes/test_client/test_adhoc_source_is_closed_after_ingest.yaml b/tests/cassettes/test_client/test_adhoc_source_is_closed_after_ingest.yaml new file mode 100644 index 00000000..23b39e99 --- /dev/null +++ b/tests/cassettes/test_client/test_adhoc_source_is_closed_after_ingest.yaml @@ -0,0 +1,44 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate, zstd + connection: + - keep-alive + content-length: + - '100' + content-type: + - application/json + host: + - localhost:11434 + method: POST + parsed_body: + encoding_format: base64 + input: + - |- + Counting + Ad-hoc fetched body. + model: qwen3-embedding:4b + uri: http://localhost:11434/v1/embeddings + response: + headers: + content-type: + - application/json + transfer-encoding: + - chunked + parsed_body: + data: + - embedding: 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 + index: 0 + object: embedding + model: qwen3-embedding:4b + object: list + usage: + prompt_tokens: 10 + total_tokens: 10 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_client/test_configured_source_is_not_closed_after_ingest.yaml b/tests/cassettes/test_client/test_configured_source_is_not_closed_after_ingest.yaml new file mode 100644 index 00000000..bab50fd1 --- /dev/null +++ b/tests/cassettes/test_client/test_configured_source_is_not_closed_after_ingest.yaml @@ -0,0 +1,44 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate, zstd + connection: + - keep-alive + content-length: + - '100' + content-type: + - application/json + host: + - localhost:11434 + method: POST + parsed_body: + encoding_format: base64 + input: + - |- + Configured + Caller-owned body. + model: qwen3-embedding:4b + uri: http://localhost:11434/v1/embeddings + response: + headers: + content-type: + - application/json + transfer-encoding: + - chunked + parsed_body: + data: + - embedding: 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 + index: 0 + object: embedding + model: qwen3-embedding:4b + object: list + usage: + prompt_tokens: 8 + total_tokens: 8 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/test_client/test_directory_ingest_skips_symlinks_escaping_the_tree.yaml b/tests/cassettes/test_client/test_directory_ingest_skips_symlinks_escaping_the_tree.yaml new file mode 100644 index 00000000..791ad797 --- /dev/null +++ b/tests/cassettes/test_client/test_directory_ingest_skips_symlinks_escaping_the_tree.yaml @@ -0,0 +1,82 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate, zstd + connection: + - keep-alive + content-length: + - '86' + content-type: + - application/json + host: + - localhost:11434 + method: POST + parsed_body: + encoding_format: base64 + input: + - Inside the tree. + model: qwen3-embedding:4b + uri: http://localhost:11434/v1/embeddings + response: + headers: + content-type: + - application/json + transfer-encoding: + - chunked + parsed_body: + data: + - embedding: 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 + index: 0 + object: embedding + model: qwen3-embedding:4b + object: list + usage: + prompt_tokens: 5 + total_tokens: 5 + status: + code: 200 + message: OK +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate, zstd + connection: + - keep-alive + content-length: + - '86' + content-type: + - application/json + host: + - localhost:11434 + method: POST + parsed_body: + encoding_format: base64 + input: + - Inside the tree. + model: qwen3-embedding:4b + uri: http://localhost:11434/v1/embeddings + response: + headers: + content-type: + - application/json + transfer-encoding: + - chunked + parsed_body: + data: + - embedding: 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 + index: 0 + object: embedding + model: qwen3-embedding:4b + object: list + usage: + prompt_tokens: 5 + total_tokens: 5 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/test_client.py b/tests/test_client.py index e6e379a2..2b29a146 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -19,6 +19,7 @@ from haiku.rag.client.documents import ( ) from haiku.rag.config import Config from haiku.rag.embeddings import EmbedderWrapper +from haiku.rag.ingester.sources.base import FetchResult from haiku.rag.store.compression import decompress_json from haiku.rag.store.models.chunk import Chunk from haiku.rag.store.models.document import Document @@ -444,6 +445,32 @@ async def test_client_create_document_from_directory(temp_db_path): assert not any("unsupported.xyz" in uri for uri in uris) +@pytest.mark.vcr() +async def test_directory_ingest_skips_symlinks_escaping_the_tree(temp_db_path): + """A symlinked file resolving outside the named directory is not ingested; + one resolving inside it is. Matches FSSource.discover.""" + import os + + async with HaikuRAG(temp_db_path, create=True) as client: + with tempfile.TemporaryDirectory() as temp_dir: + root = Path(temp_dir) / "tree" + outside = Path(temp_dir) / "outside" + root.mkdir() + outside.mkdir() + + (root / "real.txt").write_text("Inside the tree.") + (outside / "secret.txt").write_text("Outside the tree.") + os.symlink(outside / "secret.txt", root / "escape.txt") + os.symlink(root / "real.txt", root / "inside_link.txt") + + result = await client.create_document_from_source(root) + + assert isinstance(result, list) + uris = sorted(uri for doc in result if (uri := doc.uri)) + assert not any("secret" in uri or "escape" in uri for uri in uris) + assert any("real.txt" in uri for uri in uris) + + @pytest.mark.vcr() async def test_client_create_document_from_url(temp_db_path): """Test creating a document from a URL.""" @@ -2408,6 +2435,74 @@ def test_check_source_accessible_file_uri(tmp_path): assert check_source_accessible((tmp_path / "gone.txt").as_uri()) is False +class _CountingSource: + """A real Source over one in-memory document that counts its closes.""" + + def __init__(self, uri: str, body: bytes) -> None: + self.source_id = "counting" + self.supported_extensions = None + self.max_file_size = None + self._uri = uri + self._body = body + self.closes = 0 + + def supports(self, uri: str) -> bool: + return uri == self._uri + + async def head(self, uri: str) -> str | None: + return "v1" + + async def aclose(self) -> None: + self.closes += 1 + + async def fetch(self, uri: str) -> "FetchResult": + import hashlib + + return FetchResult( + uri=uri, + body=self._body, + content_type="text/markdown", + content_hash=hashlib.md5(self._body).hexdigest(), + revision="v1", + ) + + def discover(self, since=None, *, known_uris=None): + raise NotImplementedError + + +@pytest.mark.vcr() +async def test_adhoc_source_is_closed_after_ingest(temp_db_path, monkeypatch): + """An ad-hoc fetcher is built for this one call, so this call has to close + it — HTTP and WebDAV adapters hold an httpx connection pool.""" + from haiku.rag.ingester import sources as sources_module + + uri = "https://example.com/counting.md" + fetcher = _CountingSource(uri, b"# Counting\n\nAd-hoc fetched body.") + monkeypatch.setattr( + sources_module, "resolve_adhoc_fetcher", lambda *a, **kw: fetcher + ) + + async with HaikuRAG(temp_db_path, create=True) as client: + doc = await client.create_document_from_source(uri) + assert not isinstance(doc, list) + + assert fetcher.closes == 1 + + +@pytest.mark.vcr() +async def test_configured_source_is_not_closed_after_ingest(temp_db_path): + """A source handed in by the caller (the ingester's long-lived pool) is not + ours to close: closing it would tear down the pool mid-run.""" + uri = "https://example.com/configured.md" + fetcher = _CountingSource(uri, b"# Configured\n\nCaller-owned body.") + + async with HaikuRAG(temp_db_path, create=True) as client: + doc = await client.create_document_from_source(uri, sources=[fetcher]) + assert not isinstance(doc, list) + + assert fetcher.closes == 0 + + def _bbox_doc(*, with_page_image: bool, pages: tuple[int, ...] = (1,)): """DoclingDocument with one paragraph per page, each carrying a bbox.