Repository navigation
feat: add safe index configuration serialization - #780
Open
Claire-ovo wants to merge 2 commits into
Open
Claire-ovo wants to merge 2 commits into
Claire-ovo wants to merge 2 commits into
Conversation
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
SearchIndex and AsyncSearchIndex can load schemas but cannot export a portable index configuration. This adds shared serialization with connection details omitted by default. Closes #493. Thanks to @thakoreh for the earlier work in #525 / #542; this implementation revisits the URL and restore concerns raised there.
Changes
to_dict()/to_yaml()methods shared by both index classes. Schema-only output remains compatible with existing factory calls; serialization does not create a Redis client or read the environment.include_connection=True, export aconnectionmapping containingredis_url, allowlistedconnection_kwargs, andrequires_override. Strip URL userinfo, all query parameters and fragments; omit unsupported options and injected-client internals.REDIS_URL. Explicit endpoint overrides discard stored options; explicit option mappings replace rather than merge.from_existing()instances also require a replacement because those factories internally supply a client.The connection mapping and conservative omission policy are proposed for maintainer review; no format agreement is assumed. This does not add secret management or serialize live Redis data/client state.
Release Notes
Adds index configuration serialization for sync and async indexes. Existing schema-only factories remain supported. Connection exports with omitted settings require an explicit complete connection at restore time. Suggested release label:
auto:minor.Review record
Reviewed at
dd3ad554e2f5e6feaff233a6dafb74a49c41e5f3by Codex and isolated review agents usingpre-pr-review(the runtime model identifier is not exposed in this session). This implementation and review used AI assistance.Lenses: correctness (factories and sync/async parity), security (credential omission and restoration), design (public API), tests (regressions), docs (new public behavior). Skipped: Redis server behavior (no server commands, reply handling or server defaults changed).
redisvl/index/index.py:898); clarify the internally injected-client policy offrom_existing()(docs/api/searchindex.rst:59); add independent query/fragment guard tests (tests/unit/test_index_serialization.py:165). An in-memory mutation removing that guard now makes all four new cases fail; it previously passed the suite.from_existing()connections (conservative exclusion is intentional); making async-index YAML export asynchronous (the API is explicitly synchronous); accepting credential-only overrides for incomplete metadata (complete replacement avoids implicit endpoint changes).Verified on Python 3.12.14 / redis-py 8.1.0:
uv run pytest --confcutdir=tests/unit tests/unit/test_index_serialization.py tests/unit/test_schema.py tests/unit/test_index_gc_finalizer.py tests/unit/test_index_schema_type_issue.py -q -o log_cli=false --tb=short: 118 passed (80 serialization cases, 38 existing regressions).make format,make check-types: passed; mypy checked 120 source files.uv run pre-commit run --files redisvl/index/index.py tests/unit/test_index_serialization.py docs/api/searchindex.rst: passed both configured hooks;git diff --check origin/main...HEAD: passed.uv run sphinx-build -q -E -b html docs docs/_build/html: succeeded; warnings are in unchanged docs/dependency docstrings. Incremental build of the changed page also succeeded.Additional verification at the same head:
REDIS_IMAGE=public.ecr.aws/docker/library/redis:8.4 uv run pytest tests/unit/test_index_serialization.py tests/integration/test_search_index.py tests/integration/test_async_search_index.py -q -o log_cli=false --tb=short --maxfail=3passed all 179 cases (80 serialization unit cases and 99 existing sync/async index integration cases) using the unmodified repository Docker fixture. The Docker Official Images ECR mirror was used because Docker Hub resolution timed out; image digest:sha256:6a12a187547eb2eac4da4528f9d9787d69f3848e513480baedfd75e3b2ac393e.A separate manual smoke check passed 16 export/restore/create/load/fetch/count cases across sync/async, dict/YAML, HASH/JSON, and unauthenticated/password-protected disposable Redis 8.4 instances. It checked password omission and refusal to restore redacted metadata without explicit connection credentials, with a deliberately unreachable
REDIS_URLas the environment fallback. These 16 cases are manual verification, not additions to the repository test suite. Disposable indexes and containers were cleaned up.Not checked: real TLS/Sentinel/Cluster connections, provider APIs, notebooks and the full test/dependency-version matrix. Earlier Docker setup and Docker Hub pull failures occurred before assertions; the successful mirror-backed run above supersedes the former local Docker blocker. Full-repository pre-commit was also attempted: its code-quality hook passed, while pinned codespell changed the existing
Unparseablecomment inredisvl/redis/connection.py:460; that unrelated edit was reverted and the changed-file run passed. Local checks are not a claim about GitHub CI.Note
Medium Risk
Changes public factory/restore behavior for configs with
connectionmetadata and encodes security-sensitive rules around credentials and implicitREDIS_URLuse; mistakes could break deployments that relied on env-based restore after export.Overview
Adds portable index configuration export/import for
SearchIndexandAsyncSearchIndexvia sharedto_dict()/to_yaml()on the base index class. Default output stays schema-only (no Redis connection, noREDIS_URL), so existingfrom_dict/from_yamlbehavior is unchanged.With
include_connection=True, exports aconnectionblock (redis_url, allowlistedconnection_kwargs,requires_override) that strips credentials, URL query/fragment, and non-safe client options. Restoring redacted or injected-client configs requires an explicitredis_urlorredis_client—no silent fallback to the environment.from_dict/from_yamlnow accept full exported configs and apply explicit override rules (replacement URL/client drops stored kwargs; partial overrides are rejected).Docs cover serialization semantics; a large unit test suite locks down round-trips, redaction, and restore safety for sync and async indexes.
Reviewed by Cursor Bugbot for commit dd3ad55. Bugbot is set up for automated code reviews on this repo. Configure here.