Skip to content

feat(query): add exact multi-title filter (PRO-1969) - #34

Merged
gunmay-hydradb merged 5 commits into
mainfrom
chaithanya/pro-1969-title-filter
Sep 11, 2026
Merged

gunmay-hydradb merged 5 commits into
mainfrom
chaithanya/pro-1969-title-filter

Conversation

@SohamRatnaparkhi

@SohamRatnaparkhi SohamRatnaparkhi commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Linear

PRO-1969

What

Adds a repeatable --title option to hydradb query. Each value is preserved as one exact document title and forwarded to the backend, which resolves matching source IDs before running the normal query pipeline.

  • exact, case-insensitive title matching is performed by the backend
  • repeat --title to supply multiple titles
  • punctuation such as commas stays inside the title
  • blank values are rejected and case-insensitive duplicates are removed
  • ordinary title-free calls continue through the generated SDK
  • title-filtered calls use the existing authenticated API v2 transport until the SDK is regenerated with the new OpenAPI field

Dependency

Depends on hydra-db/hydradb-application#1355. Deploy the backend and complete its MongoDB index/backfill rollout first.

Checks

  • .venv/bin/python -m pytest (335 passed)
  • Ruff checks and formatting checks on all changed Python files

Signed-off-by: SohamRatnaparkhi <soham.ratnaparkhi@gmail.com>
@SohamRatnaparkhi
SohamRatnaparkhi force-pushed the chaithanya/pro-1969-title-filter branch from f4da38c to 7e3a9f0 Compare September 11, 2026 09:42
@greptile-apps

greptile-apps Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

Greptile Summary

Adds repeatable exact-title filtering to hydradb query and updates the package release references to 0.2.1.

  • Normalizes title inputs through trimming, blank rejection, and case-insensitive deduplication.
  • Uses the authenticated API-v2 transport for title-filtered requests while retaining the generated SDK path for ordinary queries.
  • Adds CLI and wrapper coverage for title forwarding and validation.
  • Updates documentation, changelog entries, package metadata, and displayed version examples.
  • Greptile automatically discovered a related ticket that helped explain the purpose of this PR: expose optional exact, case-insensitive multi-title filtering consistently through the CLI.

Confidence Score: 5/5

The PR appears safe to merge, with no outstanding blocking or non-blocking findings.

The previously reported client-side limit and missing validation coverage are fixed in the current code. The stale release examples were manually resolved without explanation, and the current README now consistently matches version 0.2.1. No new actionable failures were introduced by the changes since the previous review.

Important Files Changed

Filename Overview
src/hydradb_cli/commands/_impl.py Normalizes and validates repeatable title values before forwarding them to the query wrapper.
src/hydradb_cli/commands/canonical.py Exposes the repeatable --title CLI option and passes its values into query execution.
src/hydradb_cli/hydra/client.py Routes title-filtered queries through the authenticated raw API-v2 transport while preserving the SDK path for ordinary queries.
tests/test_cli_commands.py Covers title forwarding, whitespace normalization, case-insensitive deduplication, and blank rejection.
tests/test_wrapper.py Verifies the title-filtered request body, scope fields, endpoint, and API-version header.
README.md Documents repeatable title filtering and updates release examples consistently to version 0.2.1.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[hydradb query] --> B[Trim, validate, and deduplicate titles]
  B --> C{Titles present?}
  C -- No --> D[Generated SDK query]
  C -- Yes --> E[Authenticated API v2 POST /query]
  E --> F[Backend resolves exact titles to source IDs]
  D --> G[Normal query pipeline]
  F --> G
Loading

Reviews (6): Last reviewed commit: "docs(readme): point the install examples..." | Re-trigger Greptile

Comment thread src/hydradb_cli/commands/_impl.py Outdated
Comment thread tests/test_cli_commands.py
SohamRatnaparkhi and others added 2 commits September 11, 2026 15:21
Signed-off-by: SohamRatnaparkhi <soham.ratnaparkhi@gmail.com>
Two conflicts, both from #37 (feedback) landing on main first.

1. src/hydradb_cli/hydra/client.py — BOTH sides independently added a
   `_raw_post` helper: this branch for the titles field, #37 for /feedback.
   The implementations are identical below the signature, so the duplicate
   collapses to one. Kept main's: `json_body: Any` rather than `dict` (which
   still accepts this branch's call sites) and the docstring naming CONTRACT
   §2 rule 7. httpx sets Content-Type from `json=`, so dropping the explicit
   header changes nothing on the wire.

2. CHANGELOG.md — both sides appended under Unreleased. Kept both entries.

Everything else merged cleanly, and both features are intact: `titles` on
context.query and the _Feedback resource, each with their own tests.

354 tests + 33 conformance pass, ruff clean.

Signed-off-by: gun29may <gunmayjhingran29@gmail.com>
gunmay-hydradb
gunmay-hydradb previously approved these changes Sep 11, 2026
Comment thread pyproject.toml Outdated
Patch bump covering repeatable `--title` on hydradb query, and the
`hydradb feedback` command (#37) which main took without a bump of its own.
Nothing was removed or renamed, and no existing invocation changes.

Both places, because this package keeps the version twice -- pyproject.toml
for packaging and __init__.py for `hydradb --version` -- and nothing in the
tests or the build asserts they agree. They would drift silently, and the
one users see is the one that is easiest to forget. Verified equal after
the change, and `hydradb --version` reports 0.2.1.

Signed-off-by: gun29may <gunmayjhingran29@gmail.com>
@gunmay-hydradb
gunmay-hydradb force-pushed the chaithanya/pro-1969-title-filter branch from 32fcbef to b7320a6 Compare September 11, 2026 17:30
Greptile on #34: the package and `hydradb --version` declare 0.2.1 while
the README still told people to install 0.2.0 — a pinned installer version,
a release wheel URL, and the expected `--version` output. Someone following
those instructions would install the previous release and then see output
that disagrees with the page they were reading.

The CHANGELOG's `## 0.2.0 — 2026-07-31` heading is deliberately left alone:
that is the historical entry for that release, not a stale reference.

Verified `hydradb --version` prints exactly what the README now claims.

Signed-off-by: gun29may <gunmayjhingran29@gmail.com>
@gunmay-hydradb
gunmay-hydradb merged commit 9dba30c into main Sep 11, 2026
7 checks passed
@openhack-agent

Copy link
Copy Markdown

🔍 Security Scan Results

⚠️ 4 potential vulnerabilities detected

View full results on OpenHack

  • 🟢 Low: 4

Findings

🟢 Server-controlled strings rendered as Rich markup allow terminal output spoofing in query results and error messages

Severity: LOW

Server-controlled strings are interpolated into Rich markup-parsed output without escaping, enabling terminal output spoofing. Confirmed injection sites: (1) _feedback_hint (commands/_impl.py:87) embeds the server-supplied request_id verbatim into a markup string that _format_query_result renders via Text.from_markup at line 122; (2) print_error (output.py:97) interpolates server error body text into a markup-parsed f-string on stderr; (3) commands/_impl.py:213 embeds server request_id into a markup string passed to console.print; (4) commands/_impl.py:108 embeds chunk source_title into a markup-parsed Panel title — the highest-impact variant, since a co-tenant who ingests a document titled e.g. "[red]SYSTEM: quota exceeded[/red]" can spoof other users' query output without controlling the server. This violates the codebase's own documented convention in make_table (output.py:151-155), which explicitly escapes cells because "a title like '[draft] Q3 plan' would otherwise be read as a style tag and vanish". Impact ceiling is verified: Rich markup cannot emit arbitrary ANSI escapes or execute commands — damage is limited to recoloring, concealing text, and injecting clickable OSC-8 phishing hyperlinks (e.g. a fake "ERROR: rotate your key" line linking to an attacker URL).

Location: src/hydradb_cli/commands/_impl.py:122

View details on OpenHack →


🟢 API key echoed in full to stdout by config set when the key is 12 characters or shorter

Severity: LOW

hydradb config set api_key <value> echoes the FULL API key to stdout when the key is 12 characters or shorter. The inline masking at config_cmd.py:112-114 only masks when len(value) > 12; for shorter keys display_value remains the raw key and is printed verbatim in the success message at line 120 ("Set api_key = in ~/.hydradb/config.json"). This diverges from the shared mask_api_key() helper (utils/common.py:12-16), which returns "***" for exactly the same input — mask_api_key is already imported in config_cmd.py (line 16) and used correctly by config show (lines 45, 53); only set_value bypasses it with a buggy inline reimplementation. The full bearer key lands in terminal scrollback, CI job logs, and piped/tee'd output, defeating the feature's stated guarantee that no path prints the full key. Realistic scenario: a user or agent script following the docs' advice to pass --api-key explicitly runs hydradb config set api_key sk-abc123 in a CI job; the key is captured in the job log visible to anyone with read access to the pipeline.

Location: src/hydradb_cli/commands/config_cmd.py:112

View details on OpenHack →


🟢 Credential file written world-readable before chmod(0o600): TOCTOU window and persistent insecure mode on crash

Severity: LOW

_write_config_file() in src/hydradb_cli/config.py writes the API key with CONFIG_FILE.write_text() — which creates the file with mode 0666 & ~umask, i.e. world-readable (0644) under the default umask 022 — and only THEN calls chmod(0o600). Any local process polling the path can read the plaintext bearer key during the window between file creation and the chmod. The window recurs on every first-time config creation (login, first config set); if a previous run crashed between write and chmod (or the file was restored from backup with permissive modes), the insecure mode persists indefinitely because _read_config_file() performs no permission check and nothing else in the codebase re-checks it. Additionally, _ensure_config_dir() creates ~/.hydradb with default mkdir perms (0755), leaving the credential directory world-listable. The protected value is real: save_config(api_key=...) is invoked with the live bearer token from hydradb login (commands/auth.py:85) and hydradb config set api_key (commands/config_cmd.py:110). This is not design intent — the code comment ('Restrict permissions on config file (contains API key)') and auth.py's docstring ('stored ... with restricted permissions') show the developer intended 0600 from the start.

Location: src/hydradb_cli/config.py:91

View details on OpenHack →


🟢 Installer performs no integrity verification of release wheels and the publish pipeline allows post-tag asset replacement

Severity: LOW

The curl|bash installer performs zero integrity verification of the wheel it downloads and executes, and the release pipeline makes assets mutable, so the documented version-pinning mechanism provides no tamper-evidence. (1) install.sh builds the wheel URL (line 122), HEAD-checks only its existence (asset_exists, lines 108-117 — no hash comparison), then hands the URL directly to pipx install --force "$WHEEL_URL" (lines 147/149) or pip install --user ... "$WHEEL_URL" (lines 161/163). There is no SHA256SUMS asset, no --require-hashes, no cosign/sigstore attestation, and no GPG signature anywhere in the repo, and the README's 'Verify the installation' section only runs hydradb --version. (2) .github/workflows/publish.yml line 51 uploads artifacts with gh release upload "$TAG" dist/* --clobber, explicitly allowing a wheel to be replaced after a tag is published. Attack scenario: an attacker with maintainer-token or Actions write access re-uploads a backdoored hydradb_cli-0.2.1-py3-none-any.whl onto the already-published v0.2.1 tag; every user running the README-documented command — including the pinned form HYDRADB_CLI_VERSION=0.2.1 curl -fsSL https://cli.hydradb.com/install | bash — installs the malicious wheel, yielding arbitrary code execution with user privileges. The publish workflow itself runs unpinned pip install build twine inside a job holding a contents:write GITHUB_TOKEN, so a dependency/action compromise can silently re-upload a backdoored wheel without any commit; users auditing the tagged source would see clean code while the installed asset differs. Because 'latest' is resolved at runtime and no checksums are published, users also cannot TOFU-verify anything after the fact.

Location: install.sh:122

View details on OpenHack →

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants