feat(domains): add whoisxmlapi reverse WHOIS plugin - #111
Conversation
Sibling of whoxy-reverse-whois. searchType=current restricts matches to live registrations — verified live, exact company="Praetorian" returns 12 under current versus 164 under historic — and the free preview mode yields a match count first, so a pivot matching nothing costs no credit. Feeds the existing verifyCandidates seam, so candidates get per-candidate corroboration rather than a flat score. Ordering is not cosmetic: verifyCandidates corroborates only the first maxReverseWhoisCandidates entries and emits the rest unverified, so the sort decides which records get a lookup. Dedupe runs after the sort and keeps the first entry per domain, so a domain seen on two pages survives with its freshest observation. Records with an absent or unparseable audit timestamp sort last but are never dropped — audit dates exist only because includeAuditDates is sent true, and treating a vendor-side field change as "stale" would drop every candidate and read as "this pivot owns nothing". A purchase-page failure must not read as "no domains": preview already proved matches exist, so a failure before ANY page succeeded returns the error and only later pages degrade to partial recall. Hitting the page cap with a live cursor warns, since that path is data loss rather than a degraded score. Auth is the X-Authentication-Token header, but errors still do not wrap the vendor response — WhoisXMLAPI echoes apiKey in the request body. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CLAUDE.md Drift DetectionCode changes in this PR may have made documentation stale:
|
| Section | Issue | Evidence |
|---|---|---|
| Reverse-WHOIS Verify-After-Retrieve | Incomplete plugin list | New plugin whoisxmlapi-reverse-whois implements the verify-after-retrieve pattern (calls verifyCandidates in Run method) but isn't listed alongside reverse-whois and whoxy-reverse-whois in line 102. The section description should be updated to include all three reverse-WHOIS plugins. |
Automated drift check — please review and update if needed.
There was a problem hiding this comment.
Codex Review
Critical Issues
None.
Security
No security concerns flagged.
Suggestions
No suggestions.
Validation: I attempted go test ./pkg/plugins/domains ./pkg/plugins ./pkg/runner, but the read-only sandbox could not create Go module/build caches.
Reviewed by Codex (gpt-5.5)
There was a problem hiding this comment.
Claude Review
Critical issues
None. The plugin correctly reuses the verifyCandidates seam, sorts freshest-first before dedupe (so UniqueBy first-wins keeps the freshest observation), fails closed on a first-page purchase error while degrading to partial recall on later pages, and skips the paid call when preview returns zero. Error and pagination paths are covered by named tests.
- Minor (non-blocking): candidatesFrom sets the finding data org field to the raw query, which in email-mode is the registrant email rather than an org name, so consumers reading that field see an email under an org key. Harmless today but slightly misleading.
Security
- No concerns. Auth is via the X-Authentication-Token header (key never reaches the URL), and errors deliberately do not wrap the vendor response body since it echoes the apiKey field, both locked by the _ErrorNeverContainsTheAPIKey test. Query terms flow only into the POST body to a fixed host; no SSRF/injection surface.
Test coverage
Comprehensive: preview/purchase ordering, zero-preview credit skip, cursor paging + dedupe, null-cursor termination, old-audit-date retention, first-vs-later page failure semantics, context cancellation, and Unique/UniqueBy all have dedicated tests.
No critical issues - LGTM pending human review.
Add whoisxmlapi