Skip to content

feat(memory): wire optional Qdrant API key end-to-end#3549

Merged
bug-ops merged 1 commit intomainfrom
3543-qdrant-api-key
Apr 28, 2026
Merged

feat(memory): wire optional Qdrant API key end-to-end#3549
bug-ops merged 1 commit intomainfrom
3543-qdrant-api-key

Conversation

@bug-ops
Copy link
Copy Markdown
Owner

@bug-ops bug-ops commented Apr 28, 2026

Summary

  • Adds api_key: Option<&str> to QdrantOps::new, mirrored through EmbeddingStore::new and all three SemanticMemory constructors (~40 call sites)
  • MemoryConfig::qdrant_api_key: Option<Secret> — uses existing zeph_common::secret::Secret (Zeroizing + redacted Debug, no Serialize), matching claude_api_key precedent
  • Vault resolution via ZEPH_QDRANT_API_KEY key, extending Config::resolve_secrets (matches ZEPH_DATABASE_URL pattern)
  • Bootstrap emits tracing::warn! when Qdrant URL is non-localhost and no API key is configured
  • Init wizard prompts for key but prints vault instructions instead of persisting plaintext to config.toml
  • Migration step 39 added (no-op, field has #[serde(default)]); both MIGRATIONS.len() == 39 assertions updated
  • is_qdrant_localhost uses url::Url::host_str() for correct IPv6 bracket handling

Test plan

  • cargo nextest run --workspace --lib --bins — 8683 tests pass
  • cargo +nightly fmt --check — clean
  • cargo clippy --workspace -- -D warnings — clean
  • New unit tests: QdrantOps::new api_key paths (3 tests), is_qdrant_localhost variants (2 tests)
  • Migration step 39: 4 unit tests (adds-comment, noop-when-present, creates-section, idempotent)
  • Live test with ZEPH_QDRANT_API_KEY in vault against authenticated Qdrant instance — see playbook at .local/testing/playbooks/qdrant-api-key.md

Closes #3543

Add `api_key: Option<&str>` to `QdrantOps::new` and mirror it through
`EmbeddingStore::new` and all three `SemanticMemory` constructors (~40
call sites updated atomically). The key is consumed by the qdrant-client
builder and never stored on `QdrantOps`, so no structural leak is
possible.

Key design decisions:
- `MemoryConfig::qdrant_api_key: Option<Secret>` — uses existing
  `zeph_common::secret::Secret` (Zeroizing + redacted Debug + no
  Serialize), matching `claude_api_key` / `openai_api_key` precedent
- Vault resolution: extends `Config::resolve_secrets` via
  `ZEPH_QDRANT_API_KEY`, matching `ZEPH_DATABASE_URL` precedent
- Init wizard prompts for the key but writes vault instructions instead
  of persisting plaintext to config.toml
- `is_qdrant_localhost` uses `url::Url::host_str()` (handles IPv6
  bracket form `[::1]` correctly) to suppress false-positive WARN logs
  on localhost deployments
- Migration step 39 added (no-op: field has `#[serde(default)]`)

Closes #3543
@github-actions github-actions Bot added enhancement New feature or request size/XL Extra large PR (500+ lines) skills zeph-skills crate memory zeph-memory crate (SQLite) rust Rust code changes core zeph-core crate tests Test-related changes labels Apr 28, 2026
@bug-ops bug-ops enabled auto-merge (squash) April 28, 2026 12:40
@bug-ops bug-ops merged commit d7bb96b into main Apr 28, 2026
32 checks passed
@bug-ops bug-ops deleted the 3543-qdrant-api-key branch April 28, 2026 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core zeph-core crate enhancement New feature or request memory zeph-memory crate (SQLite) rust Rust code changes size/XL Extra large PR (500+ lines) skills zeph-skills crate tests Test-related changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

wire optional Qdrant API key end-to-end

1 participant