Commit Graph
86 Commits
Author SHA1 Message Date
RockChinQ 625ee67113 fix(ci): align workspace fixtures and constrain mobile tours 2026-10-15 05:31:04 +00:00
RockChinQ 14b5bdb8c2 feat(cloud): enforce plan policies and refine workspace interface 2026-10-15 05:31:04 +00:00
Hyu e29fd27f02 feat(i18n): localize backend messages by workspace language 2026-10-15 05:31:04 +00:00
RockChinQ b5fad9f04a feat(cloud): configure dedicated and shared worker quotas independently 2026-10-13 03:19:36 +00:00
Hyu 353b452453 fix(ci): align SDK dependency and validate acceptance migrations 2026-10-11 00:59:51 +08:00
Hyu b8a7649ac2 fix(monitoring): expire interrupted host executions using liveness leases 2026-10-10 21:30:04 +08:00
Hyu 4482e8d876 feat(telemetry)!: upload one record per execution node and one closure per chain
Core no longer assembles a whole trace locally. Every workflow node is uploaded
the moment it completes as its own `execution_node` record, and each execution
closes with exactly one `execution_chain` record; all records of one execution
carry the same `event_id`, so Space groups them back into a single chain.

- every execution starts at an inbound event: event-less Pipeline lanes and
  WebUI/API debug runs synthesize their virtual inbound event at the boundary
  and are marked debug=true, so a Runner is never a trace origin
- sampling is decided once per event from a stable hash of the event id (the
  previous `int(id[:8], 16)` raised on every `platform:`-prefixed id and so
  dropped every successful inbound-event chain) and is reported on each record
  as sample{mode,denominator}; the default mode is now `all`
- the local trace buffer, the 120s TTL, the per-process trace cap and the shared
  open-node mirror are gone, which also removes the truncated-chain upload and
  the re-buffered-closed-trace leak they caused
- a broken chain is always uploaded, and its reason falls back to the first
  failed node so the chain explains itself
- flush keeps records until the sender accepts them and counts what it drops;
  telemetry health replaces the unused send-task queue
- heartbeat reports bound Agent / plugin-processor / event-binding counts
- bound Pipeline and Agent resources (plugins, MCP servers, knowledge bases,
  tools with their Host source, skills, models and the Runner schema selectors
  that picked them) are reported on the chain record
- failure text is bounded and redacted instead of passing exception text through
- the dead per-query feature counters and their call sites are removed

Wire contract: schema 2 (`execution_node` / `execution_chain`).
2026-10-07 09:41:41 +08:00
Hyu 4c71de5eca feat(plugin): push plugin runtime ops samples to the Space control plane
The shared Cloud deployment runs one Plugin Runtime for every Workspace, but
nothing reported its health: the instance only exposed two aggregate numbers on
its own health probe, and the per-installation failure registry, the desired
state registry and the reconcile outcome lived in memory with no reader.

Add RuntimeOpsReporter, which every 30 seconds reads the Runtime ``/healthz``
probe over HTTP (derived from ``plugin.runtime_ws_url``), merges it with the
connector's desired-state, failure and reconcile summaries, and posts one
sample to the Space control plane on the existing authenticated direction.
Delivery is best-effort and bounded: a single in-flight request, a ten second
timeout, dropped samples counted in ``runtime_ops`` on the instance health
probe, and a failed probe recorded as a drop so the dashboard shows staleness
instead of grading a stale sample as healthy.

Cloud-only: a non-cloud deployment never enables the reporter, and the channel
is independent of product telemetry so ``space.disable_telemetry`` cannot blind
the ops dashboard.
2026-10-01 19:01:16 +08:00
RockChinQ 30585c8657 refactor: remove beta diagnostics collection and reporting (#2616) 2026-09-30 20:24:35 +08:00
Hyu 6ee9c0a9a3 fix(operation-trace): bind the workspace scope on every off-request write
Cloud runtime refuses unscoped database access and workspace_operation_logs is row-level-secured on the bound Workspace. The background writer, the retention pass and the metadata reads all run outside a request lifetime, so each of them failed and the failure was swallowed by the best-effort handler: enabling tracing recorded nothing at all.

The route wrapper also traces after the handler released its scope, so level resolution has to carry the Workspace itself. Without it the level read back as 0 and the request was dropped before it was even queued.

The startup gate now enumerates the Workspaces through this instance's execution bindings, because a cross-Workspace metadata scan cannot see them under RLS, and it runs after the Workspace service exists. The writer starts with a clean context so it cannot inherit the scope of the request that first enqueued a trace, and a dropped write is reported instead of being logged only at debug.
2026-09-28 22:38:35 +08:00
TyperBody ed93e7f1ac perf(operation-trace): project hash columns and make the integrity cache safe
The integrity scan selected whole rows, so a cold pass paged in the
changes/detail payloads and the client fingerprint for up to
MAX_INTEGRITY_SCAN_ROWS rows the verifier never reads. Project only the hash
columns, and add a lightweight verifier so the scan no longer builds a full
display dict per row.

Repair the read cache so it is a latency shield, not a correctness shortcut:
a result computed within INTEGRITY_CACHE_TTL_SECONDS is served from the
per-Workspace cache (opening, refreshing and paging all land inside that
window and pay nothing), while a cache miss re-verifies the whole window. An
incremental scan that skips previously verified ids can never see an edit to
an already-cached row -- exactly the tampering this feature exists to expose.
Verified against a live 414-row log: 50 content edits and 7 re-signed links
are all detected, including an edit to a row verified on a previous pass.

Also fix two correctness gaps and one maintenance bug:
- age-based prune deleted rows without invalidating the cached prefix;
- the boundary baseline is now read only when the history exceeds the scan
  window, which a bounded scan makes the rare case;
- the operation-log retention block had drifted outside the per-binding loop
  in the maintenance task, so only the last discovered Workspace was ever
  pruned while the others grew unbounded.

Tests: scan projection, verifier parity, TTL cache reuse, cache-miss
re-verification, edit to an already-verified row, hash mismatch, chain break
and prune invalidation.
2026-09-27 23:43:51 +08:00
TyperBody 9964f284e1 refactor(operation-trace): isolate subsystem, fix install identity, merge migrations
- Move the operation-traceability service and its HTTP routes into a standalone
  pkg/operation_trace package; the Core controller package no longer depends on it
  (routes stay auto-discovered by the controller package scan).
- Gate the hot path on one module-level boolean exposed as ap.operation_trace_active:
  while no Workspace has tracing enabled the route wrapper performs zero trace work
  and zero database round trips. The gate opens when a Workspace enables tracing and
  is primed once at startup for already-enabled Workspaces.
- Record the installed extension identity for GitHub / marketplace / local / upload
  installs (owner/repo, author/name, filename) so the trace no longer shows a
  nameless "a plugin was installed" event and the card names the extension.
- Merge migrations 0032 + 0033 into a single 0032_operation_traceability revision
  carrying the full table shape and an index set that matches the ORM.

Tests: unit 5165 passed / integration 358 passed; ruff check + format clean.
2026-09-27 00:11:57 +08:00
TyperBody becb6c78b4 fix(operation-trace): satisfy ruff/codeql and drop a dead summary channel
- Remove the unused request_summary local: the stored summary is derived by the
  service from changes + the classified action, so handlers publishing
  quart.g.operation_log_summary was a dead channel that never reached the row.
- Drop the unused datetime import in the operation log model.
- Apply ruff format to the touched files so `ruff format --check` passes.
2026-09-26 03:51:36 +08:00
TyperBody 78baabde96 fix(operation-trace): speed up audit reads and align i18n locales
Performance of the operation traceability surface:

- Cache the retention / row-budget / dedupe policy per Workspace and
  invalidate it on governance change, so the hot write path no longer
  issues three metadata round trips per recorded operation.
- Resolve the governance payload with one metadata query instead of four.
- Turn the dedupe probe into an existence check (LIMIT 1) instead of a
  full COUNT over the dedupe window.
- Defer the row-budget COUNT to every N inserts; prune still enforces the
  exact budget, and the maintenance loop keeps it bounded.
- Panel: fetch only the records page when paging or filtering instead of
  re-requesting governance and the filter catalogue every time.
- Export: include the effective filters (and limit) in the artifact so a
  downloaded CSV is self-describing.

Fixes and cleanup:

- Drop the unused OperationLogPruneReport import that broke `tsc`.
- i18n: remove the 9 redundant blank lines unique to en-US and format the
  six non-compliant locale files with the project Prettier config; all
  eight locales keep identical key sets, key order and placeholders.
2026-09-26 02:11:42 +08:00
TyperBody 76398c8bc4 Merge origin/master into feat/totp-two-factor-auth
Resolve the revision-graph conflict introduced by the release line.

Conflicts
- tests/integration/persistence/test_rag_document_identity.py: master had
  independently introduced the same dynamic-head helper (`current_head`) plus
  a `DOCUMENT_IDENTITY_REVISION` constant, and it explicitly upgrades to that
  revision. Keep master's semantics (the explicit revision matters because
  upgrading to the head now also traverses the TOTP branch) while keeping the
  module-level alembic imports on this branch.

New migration
- 0030_merge_totp_into_release joins the TOTP branch's own merge revision
  (0026_merge_totp_and_rag_identity) with the release head
  (0029_merge_rag_identity). Both reached 0025_rag_document_identity without
  including each other, which left Alembic with two heads and made
  `upgrade head` fail with "Multiple head revisions are present".

Verification
- Single Alembic head confirmed (0030_merge_totp_into_release).
- tests/integration/persistence/test_rag_document_identity.py: 34 passed.
- Full fast integration suite: 356 passed, 84 skipped.
2026-09-24 02:27:37 +08:00
TyperBody 8633567ce7 feat(auth): add TOTP two-factor authentication
Add a per-Account time-based one-time password (TOTP) second sign-in
factor, plus the owner/admin tooling needed to operate it.

Backend
- TotpService: enrolment, constant-time verification with a +/- one step
  drift window, single-use recovery codes and disablement.
  * shared secret is only ever persisted as a Fernet token whose key is
    derived (HKDF-SHA256) from the instance JWT secret and gated by a
    key_version epoch;
  * recovery codes are only ever persisted as salted
    PBKDF2-HMAC-SHA256 digests (600k iterations) and are single-use;
  * the consumed counter advances monotonically so a captured code cannot
    be replayed inside the same time window.
- New persistence entities and alembic migrations for credentials and
  recovery codes.
- Login second-factor challenge, bound to the Account that passed the
  password step.
- Owner/admin oversight endpoints to inspect and re-bind the second
  factor of any Account.

Frontend
- Account settings panel for enrolling, managing, re-binding and
  disabling the second factor.
- Login second-factor step and the matching client methods.
- Strings for all eight locales.

The shared secret never crosses the API boundary: enrolment returns a
server-rendered QR code (as a data: URL) and the plaintext secret is
discarded as soon as the image is produced.
2026-09-24 01:31:54 +08:00
RockChinQ 27871e4363 merge: integrate master certification and document identity fixes into 4.11 2026-09-21 10:55:40 +00:00
RockChinQ 942a302808 fix(plugin): load certification key ring from env (#2554) 2026-09-20 22:22:32 +08:00
RockChinQ 20a04a77bf feat(plugin): enforce certified archive admission (#2553)
* feat(plugin): add certified admission policy

* feat(plugin): enforce certified archive admission

* chore(plugin): pin certified SDK beta

* fix(plugin): consume SDK beta 5

* style(plugin): format certification admission
2026-09-20 18:54:45 +08:00
RockChinQ 273b1ea3cf Merge master into dev/4.11.x and preserve plugin runner architecture
Reconcile migration branches without rewriting published revisions; retain additive Codex, monitoring, provider and platform fixes. Keep dynamic runner schemas and Host ownership, restore compatibility regressions, and preserve safe model-test error handling.
2026-09-16 08:13:07 +00:00
BiFangKNT a32b3121d3 build(boot): register xxhash in startup dependency check 2026-09-15 18:14:29 +08:00
dadachann f8123ead0a feat(telemetry): add isolated beta quality diagnostics and release identity 2026-09-15 09:35:01 +00:00
RockChinQ f24a7c9bb2 feat(runner): unify plugin execution across agents and event processors 2026-09-10 18:04:38 +08:00
Tynwink 1ba3c1ec72 Merge pull request #2520 from langbot-app/feat/api-key-system-context
为 lbctl 增加 API Key 发现与管理能力
当前为 lbctl 提供的能力通过 system.py -> SYSTEM_CAPABILITY_OPERATIONS 维护,后续可通过统一的接口暴露能力,避免频繁维护常量。
2026-09-09 14:47:00 +08:00
Tynwink2000 1a69747a06 feat(api): expose task status to api keys 2026-09-08 14:06:13 +08:00
267232c24f fix(security): harden password recovery with usable eight-character codes (#2477)
Use eight securely random recovery-code characters with concurrency-safe online throttling. Preserve existing keys and verify recovery through browser and real SQLite integration tests.

Co-authored-by: [email protected] <[email protected]>
Co-authored-by: dadachann <[email protected]>
2026-09-07 15:31:54 +00:00
Hyuanddadachann 1cfe87186c docs: update published documentation links (#2509)
Co-authored-by: dadachann <[email protected]>
2026-09-05 00:55:18 +08:00
dadachann 0559d9d441 Merge master into dev/4.11.x
# Conflicts:
#	pyproject.toml
#	uv.lock
2026-08-24 02:34:14 +00:00
dadachann 6bf1546df2 style: format Cloud runtime readiness fixes 2026-08-20 19:08:41 +00:00
dadachann 0bec72a3f9 fix(cloud): run runtime initialization outside transaction gate 2026-08-20 18:55:24 +00:00
dadachann f36542135a fix(cloud): start API before runtime reconcile 2026-08-20 18:55:24 +00:00
dadachann 693c59b726 fix(cloud): import lifecycle task scope 2026-08-20 18:55:24 +00:00
dadachann c3fe312a43 fix(cloud): refresh directory during plugin startup 2026-08-20 18:55:24 +00:00
Junyan Qin f94243c725 chore: merge master into dev/4.11.x 2026-08-14 16:04:52 +08:00
HyuandChan c67a503532 feat(health): expose plugin runtime readiness (#2420)
Co-authored-by: Chan <[email protected]>
2026-08-12 19:49:56 +08:00
HyuandChan ddb6dbf593 fix(cloud): tolerate slow plugin runtime reconciliation (#2405)
Co-authored-by: Chan <[email protected]>
2026-08-06 20:39:20 +08:00
huanghuoguoguo 679b8346cb Merge remote-tracking branch 'origin/master' into dev/4.11.x
# Conflicts:
#	pyproject.toml
#	src/langbot/pkg/pipeline/controller.py
#	uv.lock
#	web/src/app/home/bots/components/bot-form/BotForm.tsx
#	web/src/app/home/components/home-sidebar/HomeSidebar.tsx
#	web/src/app/home/components/home-sidebar/SidebarDataContext.tsx
#	web/src/app/home/plugin-pages/page.tsx
#	web/src/app/infra/entities/api/index.ts
2026-08-04 12:16:27 +08:00
Hyuanddadachann d64278ab3f feat(cloud): provision workspace model catalog (#2376)
* feat(cloud): provision workspace model catalog

* ci(cloud): pin model catalog adapter source

* fix: make cloud model catalog sync recoverable

* ci: pin cloud adapter source for release

---------

Co-authored-by: dadachann <[email protected]>
2026-08-01 18:16:02 +08:00
huanghuoguoguo e589683b98 Merge remote-tracking branch 'origin/master' into dev/4.11.x
# Conflicts:
#	src/langbot/pkg/pipeline/process/handlers/chat.py
#	tests/integration/persistence/test_workspace_migration.py
2026-08-01 09:31:23 +08:00
huanghuoguoguo 55f42a4ebc chore(merge): sync master into dev/4.11.x 2026-07-31 19:29:38 +08:00
Hyuanddadachann 404e3466d9 feat(cloud): add scoped support admin sessions (#2369)
* feat(cloud): add scoped support admin sessions

* style(web): format support admin session changes

* fix(cloud): isolate support adapter sessions

* fix(cloud): authenticate plugin assets and report workspace resources

---------

Co-authored-by: dadachann <[email protected]>
2026-07-31 17:41:55 +08:00
Hyuanddadachann 5ec2371879 fix(config): preserve typed list environment overrides (#2367)
Co-authored-by: dadachann <[email protected]>
2026-07-31 16:06:09 +08:00
RockChinQanddadachann e1ac5e0fc8 feat(tenancy): add Workspace multi-tenant foundation (#2353)
* Document multi-tenant workspace architecture

* Add OSS and commercial workspace boundaries

* docs: redesign multi-tenant workspace architecture

* feat(tenancy): implement workspace isolation

* docs(tenancy): record verification evidence

* docs(tenancy): revise single-instance SaaS topology

* docs(tenancy): refine architecture options

* docs: finalize cloud v2 multi-tenant decisions

* feat(tenancy): establish cloud isolation foundations

* feat(tenancy): harden shared cloud runtime boundaries

* docs(tenancy): record final isolation verification

* fix(tenancy): close isolation and permission gaps

* docs(tenancy): record final isolation verification

* feat(tenancy): connect cloud workspace control plane

* fix(build): install git for pinned SDK

* docs(cloud): update control plane verification

* chore: update multi-tenant SDK pin

* fix(cloud): skip legacy model sync during startup

* test(cloud): preserve minimal model manager fixtures

* fix(cloud): preserve authenticated account context

* fix(cloud): reuse authenticated account for user info

* feat(cloud): complete Workspace settings navigation

* test(web): cover Workspace dropdown menu

* feat(web): place workspace controls in sidebar

* refactor(web): streamline workspace controls

* style(web): format workspace layout test

* fix(cloud): surface runtime and workspace plan status

* fix(plugin): keep runtime identity stable across restarts

* fix(ui): widen and center workspace switcher

* fix(ui): hide roles from workspace switcher

* fix(ui): align workspace switcher with sidebar entries

* feat(workspace): add in-product collaboration and direct Cloud launch

* style: format collaboration changes

* fix(workspace): bind collaboration APIs to tenant UoW

* fix(cloud): preserve Core-owned collaboration state

* test(cloud): require Space identity for invite registration

* feat(cloud): complete secure invitation experience

* style(web): format invitation flows

* fix(cloud): recover box runtime without unscoped skill reload

* feat(oss): enforce invitation account and owner billing flows

* style: format OSS account service

* test(oss): cover invitation logout handoff

* fix(oss): resolve workspace owner in scoped session

* feat(cloud): harden multi-tenant runtime resources

* fix(cloud): bound runtime restart storms

* fix(cloud): eliminate periodic runtime CPU spikes

* fix(cloud): enforce instance capacity ceilings

* fix(cloud): scope public login capability discovery

* fix(cloud): bound tenant maintenance and monitoring work

* fix(runtime): bound tenant resource amplification

* fix(deps): pin green multi-tenant plugin SDK

* fix(cloud): handle unavailable skill capability

* fix(security): require authentication for image file endpoint (H-2)

- Changed /api/v1/files/image from AuthType.NONE to USER_TOKEN_OR_API_KEY
- Added Permission.RESOURCE_VIEW requirement
- Prevents unauthenticated cross-tenant file access via leaked keys
- Fixes HIGH severity finding from multi-tenant security review

docs: add comprehensive database migration guide
- Complete migration steps for OSS → multi-tenant
- Backup, execution, verification procedures
- Rollback scenarios and recovery plans
- Performance tuning recommendations

* test: add comprehensive cross-tenant isolation tests

Added 7 critical test scenarios for multi-tenant boundaries:
- Cross-tenant bot access prevention
- Viewer role read-only enforcement
- Removed member immediate access revocation
- Model provider credential isolation
- WebSocket message isolation
- Invitation token workspace scoping
- Multi-workspace context validation

These tests address P0-2 coverage gaps for:
- workspaces.py (membership & invitation flows)
- user.py (authentication & authorization)
- websocket_chat.py (real-time isolation)
- plugins.py (resource access control)

docs: finalize database migration guide

* fix(security): resolve M-1, M-2, M-3 security findings

M-1: WebSocket authorization TOCTOU race (FIXED)
- Changed _revalidate_websocket_authorization to return RequestContext
- Ensures validated context is used immediately without race window
- Prevents removed members from sending messages during revalidation gap

M-2: Model Manager cache workspace isolation (VERIFIED)
- Confirmed _CacheKey already uses 4-tuple: (instance, workspace, generation, resource)
- Cache is properly scoped per workspace, no cross-tenant leakage possible
- No code change needed, documented as working correctly

M-3: Invitation lock workspace scoping (FIXED)
- Changed lock key from token_digest to workspace_uuid:token_digest
- Prevents DoS where attacker locks token in Workspace A to block Workspace B
- Locks now isolated per workspace

All MEDIUM severity findings from security review now resolved.

* fix(cloud): unblock tenant CI and enforce knowledge quotas

* fix(tenancy): scope rerank model sync

---------

Co-authored-by: dadachann <[email protected]>
2026-07-30 21:43:35 +08:00
Junyan Qin 998b76d53a fix(runtime): make plugin and box connectors resilient 2026-07-21 18:43:24 +08:00
Junyan Qin 1765c43262 Revert "fix(runtime): make plugin and box connectors resilient"
This reverts commit 0b461e5830.
2026-07-21 18:43:01 +08:00
Junyan Qin 0b461e5830 fix(runtime): make plugin and box connectors resilient 2026-07-21 18:41:22 +08:00
huanghuoguoguo d88d05e27c feat(agent-runner): enforce 4.x host-owned execution 2026-07-19 22:46:01 +08:00
Junyan Qin 27b43c1731 feat(agent): add event orchestration surface 2026-07-19 22:41:30 +08:00
huanghuoguoguo cb9930c9e4 feat(agent-runner): add plugin runner host integration 2026-07-19 22:41:30 +08:00
RockChinQ b7d8332cb0 feat(telemetry): include instance_create_ts in heartbeat payload
Load the instance creation timestamp from data/labels/instance_id.json
(backfilling+persisting it for instances created before the field existed),
expose it as constants.instance_create_ts, and include it in the heartbeat
payload so Space can anchor Time-To-Value / onboarding analytics on real
install time rather than first-heartbeat.

Verified: py_compile, ruff, pytest tests/unit_tests/telemetry/ (37 passed).
2026-06-13 11:13:18 -04:00