Files
wehub-resource-sync 7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

11 KiB
Raw Permalink Blame History

🔒 Security

  • Raw exception variables (e, exc, etc.) are no longer interpolated directly into logger.exception() messages across all LLM provider, embedding provider, and web search engine paths; each catch site now scrubs the message through sanitize_error_message()/redact_secrets() before logging, preventing error text from leaking API keys, credentials, or internal URL structure into production logs. Scrubbed exception log lines now include the exception class name so exceptions that stringify to an empty message still produce useful diagnostics. A new check-sensitive-logging pre-commit hook enforces this rule going forward, rejecting direct exception-variable interpolation in the secure-logging directories and flagging exc_info=True on warning/error/critical calls. (#4888)
  • NewsAPIException.to_dict() now redacts credential shapes from the fields it serializes to the client through the two @errorhandler(NewsAPIException) handlers: the human-readable message goes through the central sanitize_error_for_client(), and string leaves of details go through sanitize_error_message(). This is a defence-in-depth backstop at the response boundary — the primary defence stays at the news/api.py raise sites (curated generic messages, #4843) — so a future raise site, subclass, or external caller that lets a credential-bearing string into message or details (e.g. the caller-supplied search query forwarded in details) has it redacted before it ships. Redaction is credential-shape based (Bearer/Authorization, ?api_key=-style params, known token prefixes, http(s) URL userinfo), so legitimate text is unchanged; error_code / status_code are left untouched. It does not attempt to catch DSN userinfo (postgresql://user:pass@), SQL, or filesystem paths — those remain the responsibility of the raise-site discipline. (#4931)
  • The central credential sanitizer (sanitize_error_message / sanitize_error_for_client) now redacts URL userinfo credentials in any scheme (case-insensitive), not just http(s). Raw URL-form database connection errors — SQLAlchemy dialect+driver DSNs (postgresql+psycopg2://user:pass@host, mysql+pymysql://…, mongodb+srv://…), plain DB schemes, and password-only DSNs (redis://:pass@host) — previously leaked their password through any surfaced exception message; the password is now replaced with [REDACTED]. Credential-less DSNs with a port (postgresql://host:5432/db) and all existing http(s) behavior are unchanged. Key=value DSNs (e.g. pyodbc Server=...;Pwd=...) have no :// and remain out of scope for a userinfo regex. This benefits every consumer of the central sanitizer (download service, fetch tool, agent strategies, search engines, and the news error-response backstop). (#4933)
  • WebAPIException.to_dict() now redacts credential shapes from the fields it serializes to the client (message via sanitize_error_for_client(), details string leaves via sanitize_error_message()), mirroring the NewsAPIException backstop. This is a defence-in-depth measure at the response boundary so that a future raise site, subclass, or external caller that lets a credential-bearing string into message or details has it redacted before it ships. Legitimate text is unchanged, and status / error_code / status_code are left untouched. (#4937)
  • The egress guardrail now enforces a two-axis (data-sensitivity × destination-exposure) admissibility rule at the start of a research run (ADR-0007): the run is refused when a sensitive source (a private collection/library/store) would reach an exposing sink (a public search engine or a cloud LLM/embeddings provider), in addition to the existing scope checks. Override by setting Egress Scope to Unprotected, marking the collection public, or trusting the destination.

New Features

  • New Zotero integration: import a Zotero library or collection into your document library, with optional background auto-sync. Add your Zotero API key, library type/ID and (optionally) a collection key under Settings → Zotero, then use the new Library → Zotero page to test the connection, list collections, and Sync now. Imported papers are stored, text-extracted and RAG-indexed like any other library document, so they become searchable during research via the collection search engine — no separate search engine to configure. Sync is incremental (new, changed and removed items are reconciled), and items without an attached PDF are imported as metadata/abstract text by default (toggle off to import PDFs only). Enable Auto-Sync to refresh in the background on a configurable interval. (#4723)
  • Zotero integration polish from first real-world testing: standalone PDF attachments (PDFs added without a parent item) now import as documents; the library ID is auto-detected from the API key (usernames resolve too); manual syncs re-examine previously skipped items; imports appear in the main Library view; a live progress bar tracks syncs; the config page autosaves with essentials-first layout and runs the connection test on saving a key; friendlier defaults (text-only PDF storage, integration enabled once a key is set) and actionable error messages. (#4960)
  • Add a per-category entry counter next to each filter button in the Research Logs panel (All, Milestones, Info, Warning, Errors). Counts reflect entries currently rendered in the DOM and update on insert, prune, and batch load, so users can see at a glance which categories still have entries when the global DOM cap is hit.
  • Add an Unprotected egress scope — an explicit opt-out that disables the egress-scope restrictions for a run (the hard SSRF and cloud-metadata blocks still apply), surfaced with a light-red panel and a non-dismissible "protection disabled" banner. The rarely-used Both scope is retired: it is removed from the selector, and existing saved both values are migrated to Adaptive (a residual value is also coerced to Adaptive at read time). If you relied on both to run a private collection with a cloud model, mark that collection public or choose Unprotected.
  • Add per-destination trust to the egress model (ADR-0007): policy.trusted_inference_providers and policy.trusted_search_engines let you mark specific off-machine LLM/embeddings providers or search engines as trusted, so the two-axis classification treats them as contained (e.g. a zero-retention enterprise Anthropic endpoint, or a self-hosted Elasticsearch/Paperless on a public hostname). A banner surfaces active trust entries.

🐛 Bug Fixes

  • Registration no longer leaves a bricked account behind: if creating the encrypted user database fails after the auth row is committed, both the orphaned auth row and any partial on-disk database files (including the per-database salt) are now cleaned up, so the username is genuinely reusable on retry. (#4934)

  • The settings write API now rejects malformed keys (a trailing dot like local_search_chunk_size., a leading dot, an empty .. segment, or blank/whitespace) with HTTP 400 instead of silently persisting them. Such rows made get_setting() return a {"": value} wrapper dict that rendered as [object Object] on settings pages (#4840). The manager (set_setting, create_or_update_setting) also refuses to create malformed keys, and import_settings skips them so a corrupted export can't reintroduce them. Complements the read-side fix in #4852. (#4935)

  • Registration now recovers from an orphaned per-database salt file (left with no matching database by a prior interrupted registration), so a username that was previously stuck as un-registerable can be registered again. (#4942)

  • Both settings prefix-read paths — SettingsManager.get_setting (DB) and get_setting_from_snapshot (the snapshot path used by research threads) — now filter out malformed rows (e.g. a legacy foo.. or foo. key), so a stray malformed row can no longer turn a leaf read into a {".": value} wrapper dict that renders as [object Object]. Completes the read side of #4840 beyond #4852's exact single-trailing-dot exclusion; existing malformed rows remain harmless and are not deleted. (#4946)

  • Fix the 'Info' filter button in the Research Logs panel being a silent no-op. Clicking it left the panel showing every entry (warnings, errors, milestones) because the visibility helper returned true for all log types when the active filter was 'info'. The filter now narrows to info entries only, matching the button's label.

  • Fixed a 3050 second visible lag between clicking Stop and a focused-iteration research actually stopping. FocusedIterationStrategy.analyze_topic now calls self.check_termination() at the start of every iteration, after the parallel search (before optional verification searches), and just before the final synthesis LLM call, so a cancellation request is detected within the current iteration rather than only at the next iteration's progress emit.

  • Fixes a subtle data-loss bug in the Research Logs panel: identical warning, error, and milestone entries were being collapsed into a single (N×) counter, the same way repetitive info entries like "Status: OK" already were. Collapsing diagnostic entries like that strips the recency signal — after the second identical error you can no longer tell when the last failure happened, and repeated retries look like a single stuck event instead of forward progress.

    The content-dedup scan now applies only to info entries (where collapsing repetitive noise is useful). Warning / error / milestone entries always render. The id-based dedup earlier in the pipeline still catches exact retransmits with the same id, so the bypass is strictly about content-similar-but-distinct-events getting the same timestamp.

📝 Other Changes

  • Fixed broken copy-paste examples in the README and docs (benchmark CLI module path, rate_limiting reset --engine, nonexistent openclaw search engine) plus two dead external links, and added a pre-commit check that keeps README links, anchors, and examples in sync with the codebase. (#4950)