Exposes the agent to OpenBB Workspace over the openbb-ai SDK, behind an
optional `openbb` extra.
Security repairs on top of the contribution:
- pro.openbb.co is no longer a default CORS origin. CORS is installed
globally with credentials and keyless loopback mode admits safe GETs by
peer address, so that default would have let scripts on the OpenBB
origin read /sessions and /runs. Extra origins are now an additive
opt-in (VIBE_TRADING_EXTRA_CORS_ORIGINS) declared in the typed config
layer; the loopback-only defaults are unchanged.
- POST /v1/query carries require_auth. It reaches the full agent registry,
which auto-registers the order tools, so an unauthenticated caller could
have driven actions inside an already-active mandate.
- The three unadvertised LLM routes (chat title, dashboard title, prompt
enhancement) are removed rather than authenticated: they were absent
from the manifest and duplicated the existing authenticated title path.
- Conversation identity no longer hashes the first message. Any two
conversations opening with the same text mapped onto one persistent
session, leaking history between them, and later requests' full history
was ignored. openbb-ai 2.1.0 exposes no conversation id, and the SDK
contract is stateless with full history per request, so each request now
runs an ephemeral session replaying the supplied history.
- The SDK is wired into the dev install and CI, with an explicit import
check. It previously landed only in agent/requirements.txt while CI
installs the extras, so every bridge test silently skipped and the
feature could look green while being uninstallable.
- Workspace context is now ingested under an 8k budget instead of ignored,
and widget-dashboard-search is advertised as false: widget groups carry
metadata only, and the value round-trip is not implemented, so the model
is told values are absent rather than left to invent them.
The contributor's requirements-lock.txt rewrite was dropped (stale
Python-3.12 regen with unrelated downgrades; the runtime targets 3.11).
Note for operators: a browser POST from a remote Workspace origin is still
refused by the pre-existing cross-site guard, independently of CORS and of
a valid token. Self-hosted same-origin Workspace and server-side callers
work; that boundary is pinned by a test.
React Router 7.12.0 through 8.2.x carry a high-severity RSC-mode CSRF bypass
(GHSA-qwww-vcr4-c8h2). We were on 7.18.1, inside that range. The advisory is not
reachable here — the app is a client-side SPA on createBrowserRouter with no
@react-router/server and no RSC entry point, and the frontend ships as static
Vite output — but 7.18.1 is the final 7.x release, no backport exists, and 8.3.0
is the only patched version, so staying put means staying on an EOL line with a
permanent open alert.
react-router-dom has no 8.x at all; the DOM exports moved into react-router
itself. So the dependency is swapped and every import rewritten. All ten APIs in
use here are unchanged in 8.3.0, and none of the data-layer surface that changed
most between majors is used.
react-router 8 requires Node >=22.22.0, which is the same wall that had jsdom 30
and @testing-library/jest-dom 7 sitting in the Dependabot ignore list. Node 20
reached EOL on 2026-04-30, so the toolchain moves to Node 22 across CI, the wiki
workflow, the Dockerfile and docker-compose. That unblocks all three at once:
jsdom and jest-dom are taken here too, and their ignores are removed rather than
left carrying a rationale that no longer holds.
Verified on the frontend suite: tsc -b and vite build clean, 310 tests across 35
files pass before and after the jsdom/jest-dom bumps.
Add task-scoped cancellation, reject broad Python process-name kills, expose timeout context, and cover the lifecycle on Windows 11 and Windows x64 with Python 3.14.
Signed-off-by: Haozhe Wu <haozhe_wu@connect.hku.hk>
Implements VT-001 through VT-010 from the 2026-07-10 external security
audit (Trivy/Semgrep/ZAP/Gitleaks/pip-audit against a real deployment):
- VT-001 (Critical): AST hardening in backtest/runner.py rejects
network/subprocess/eval/os.environ/unsafe-open calls reachable from
generated SignalEngine method bodies (previously only checked
top-level statements). Defense-in-depth: ephemeral per-run HOME,
RLIMIT_AS/NOFILE caps, best-effort UID-drop to a new vibe-sandbox
user (currently inert under Docker's cap model - see session doc;
accepted as documented residual gap, primary AST defense unaffected).
- VT-002: multi-stage Dockerfile split so build-essential never
reaches the runtime image.
- VT-003: SSE auth moved from a long-lived API key in the URL query
string to short-lived single-use tickets; access-log redaction for
any remaining query secrets.
- VT-004: agent/.env split-brain fixed (bind mount + atomic 0600
writes) between docker-compose and Web UI settings writes.
- VT-005: /correlation now requires auth + per-IP rate limit; generic
exceptions no longer leak raw text to clients.
- VT-006: CSP-Report-Only + security headers middleware; Google Fonts
replaced with self-hosted @fontsource packages.
- VT-007: docker-compose hardening (cap_drop ALL + minimal cap_add,
no-new-privileges, read_only rootfs, resource limits).
- VT-008: /health split into /live (liveness) and /ready (real
provider-config readiness check); /health kept as a compat alias.
- VT-009: base images pinned by digest, GitHub Actions pinned by
commit SHA, dependabot.yml added, hash-verified requirements-lock.txt
now actually wired into the Docker build via --require-hashes.
- VT-010: universe-panel pickle cache sidecar upgraded from an
unkeyed SHA-256 (forgeable by anyone with cache-dir write access)
to a keyed HMAC.
Implemented via a 5-parcel Workflow (file-disjoint, independent
adversarial verification per parcel, then a holistic final audit).
The final audit caught a real regression (CI env-var-gate violation)
and confirmed a dependency-pinning gap, both fixed and re-verified
here, including a latent transitive-dependency bug the fix surfaced
(smartmoneyconcepts<0.0.27 pulls an unbuildable zigzag package) - see
docs/sessions/2026-07-13_session_vt476_security_hardening.md (local,
gitignored) for full evidence trail.
Full suite: 5191 passed, 6 pre-existing/environmental failures
(unchanged from main). Docker build + hardened compose boot verified
end-to-end.
Reverts merge commits 0b867a7 (#405) and 474f5e4 (#416), and removes the
now-orphaned #406 artifact metadata store (src/reliability + tests, zero
references left outside its own tests).
Why: the stack wrapped the tool registry in every session path (even
governance mode=off) without exposing the registry surface AgentContext
reads, breaking all session-runtime chats within a day (#433, #431). It
also modified protected core files (src/agent/loop.py, src/session/
service.py), shipped 12 internal-convention docs/ files into the public
tree, and its enforcement layer already has reported bypass paths (#420).
Trading safety stays on the single mandate-gate design (#31, #144).
README news entries for 2026-07-07/07-06 updated accordingly.
GitHub forces Node 20 actions onto the Node 24 runtime starting 2026-06-16
and removes Node 20 from runners on 2026-09-16. Bump the three first-party
actions to their latest Node-24-native majors across all workflows:
- actions/checkout v4 -> v6
- actions/setup-python v5 -> v6
- actions/setup-node v4 -> v6
Inputs are unchanged (node-version "20" is the frontend JS runtime, not the
action runtime). Third-party cloudflare/wrangler-action is out of scope.
Cherry-picked the test-infra commit from #175 (sambazhu): vitest setup + 19 frontend test files (197 tests), backend auth/path-traversal/CORS tests, yfinance crypto fallback (BTC-USDT->BTC-USD), and CI coverage + frontend-test steps. Dropped the PR's separate i18n commit to stay consistent with #163.
Fix: align @vitest/coverage-v8 to ^3.2.6 (was ^4.1.8, incompatible with vitest ^3.2.6 - blocked npm install and the new npm ci CI step).
The CLI was split into a package in b5a44a1; the workflow still
ran ``python -m py_compile cli.py`` against the now-renamed file
and failed with "No such file or directory: 'cli.py'".
Use ``python -m compileall -q cli`` so every module under the
package (``main.py``, ``_legacy.py``, ``commands/``, ``components/``,
``utils/``, ``_version.py``, ``__main__.py``) is checked together.
Bug fixes
- CompositeEngine no longer misroutes bare Chinese-futures codes like
RB2410 to GlobalFuturesEngine. _is_china_futures moved into a shared
_market_hooks module with a case-normalized product table and a
non-CN exchange guard. 9 new regression cases (RB2410 / rb2410 /
RB2410.SHFE / CL.NYMEX / M2412.CBOT / CF2412.ICE / AU2412.COMEX /
FG2412.EUREX / bare CN-collision still routes Chinese).
- Session FTS5 indexes now persist timestamps so cross-session search
can sort by date. Same path also fixes a re-upsert that was
wall-clocking every session's started_at on title-rename.
- Vite dev-mode proxy gained the missing /alpha entry; AlphaZoo page
resolves on npm run dev.
Cleanup
- Deleted swarm/api_models.py + swarm/mailbox.py + SwarmDashboard.tsx
(dead modules / orphaned UI after swarm-via-agent flow).
- Deleted SessionService.resume_attempt + get_attempts + get_attempt
+ SessionStore.list_attempts + Attempt.mark_waiting_user chain
(half-baked human-in-the-loop from initial commit).
- Deleted ChatLLM.achat (async sibling never called) and
_extract_balanced_json (only-tested helper).
- Deleted american_exercise_value in options_portfolio.py
(driver inlines bs_price logic).
- Deleted _compute_ic_series_reference in factor_analysis_core.py
(kept-as-reference, no callers).
- Collapsed MEMORY_TYPES duplication between cli.py and
memory.persistent; restored set-equality invariant assert.
- Deleted runSwarm (~197 LOC), swarmDash state, swarmCancelRef
write-only ref (orphaned by new agent-driven swarm flow).
- Dropped 76 unused 'vw = vwap(...)' boilerplate lines across
gtja191 alphas + their now-unused vwap imports.
- Cleared 11 F401 unused-import sites in tools/, agent/, providers/.
Test infrastructure
- test_e2e_harness_v2.py (real-LLM e2e) gated behind
VIBE_TRADING_RUN_LIVE_E2E so CI no longer flips shape based on
env-key presence. CI workflow now has explicit --ignore.
- test_auto_compact_with_long_history: monkeypatch TOKEN_THRESHOLD so
the test deterministically triggers compact instead of relying on
unrelated LLM behaviour.
- test_compact_tool_explicit: assertion corrected — compact tool is
special-cased in loop._process_tool_calls and does NOT emit
tool_call events. Assert on the 'compact' event instead.
- TestSwarmE2E: per-test @pytest.mark.timeout overrides matching the
internal 300s poll deadlines; cancel test now polls for terminal
state instead of fixed sleep(3).
Tooling
- ruff per-file-ignores for factors/zoo/** (3783 → 0 F401 noise);
F841 stays active in zoo to catch real formula bugs.
- frontend tsconfig: noUnusedLocals + noUnusedParameters as
regression guards.
- highlight.js hoisted to direct dependency (was transitive via
rehype-highlight).
- Vite proxy: dropped unused /run, /skills, /health, /api, /system;
added /alpha.
Annotations
- direction parameter renamed to _direction in 6 calc_commission
signatures (reserved for future borrow-fee asymmetry).
- _MARGIN_PER_CONTRACT in global_futures.py annotated as reference
data.
- Backtest engines' _calc_pct_change variants cross-reference each
other in docstrings.
Docs
- 2026-05-18 news entry added to README.md / README_zh.md /
README_ja.md / README_ko.md / README_ar.md; 2026-05-15 entry
rolled into the Earlier news <details>.
- Contributors heading: v0.1.7 cycle → v0.1.8 cycle in all 5
READMEs.
126 files changed, +363 / -1276.