mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-09-01 09:09:19 +00:00
* feat: add WASM extension versioning with WIT compat checks and CI enforcement Phase 1 — WIT Versioning & Compatibility Checks: - Version WIT packages as `package near:[email protected];` - Add `semver` crate for version parsing and comparison - Add `WIT_TOOL_VERSION` / `WIT_CHANNEL_VERSION` host constants - Add `version` and `wit_version` fields to capabilities schemas - Add `wit_version` column to `wasm_tools` DB table (both backends) - Add load-time `check_wit_version_compat()` with semver rules - Add `IncompatibleWitVersion` error variants for tools and channels - Enhance instantiation errors with WIT version mismatch hints - Update all 14 capabilities JSON and 14 registry JSON files Phase 2 — Upgrade-in-Place & Channel DB Storage: - Change tool store to DELETE-before-INSERT (one version per extension) - Create `wasm_channels` table (PostgreSQL migration + libSQL schema) - Add `WasmChannelStore` trait with PostgreSQL and libSQL backends - Add `extension_info` tool showing version, WIT version, and status - Wire `ExtensionInfoTool` into tool registry (7 extension tools) Phase 3 — CI Version-Bump Enforcement: - Add `scripts/check-version-bumps.sh` checking WIT/tool/channel versions - Add `version-check` CI job (PR-only) to `.github/workflows/test.yml` - Support `[skip-version-check]` label/commit message bypass Includes 7 regression tests for WIT version compatibility checking and 2 integration tests for WIT version annotation verification. [skip-regression-check] Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: address PR review feedback for WASM extension versioning - Wrap PostgreSQL DELETE+INSERT in transactions for both tool and channel store() methods to prevent data loss on partial failure (Gemini, Copilot) - Rename StoredWasmChannelWithBinary.tool → .channel (copy-paste fix) - Remove unused WasmError::IncompatibleWitVersion variant (dead code) - Map channel loader WIT mismatch to IncompatibleWitVersion instead of generic Config error, simplify variant to single String message - Fix extension_info description to match actual returned fields - Add schema test for ExtensionInfoTool matching existing test pattern - Fix CI script to fail fast on git errors instead of silent bypass [skip-regression-check] Co-Authored-By: Claude Opus 4.6 <[email protected]> --------- Co-authored-by: Claude Opus 4.6 <[email protected]>
109 lines
6.7 KiB
Rust
109 lines
6.7 KiB
Rust
//! WASM-extensible channel system.
|
|
//!
|
|
//! This module provides a runtime for executing WASM-based channels using a
|
|
//! Host-Managed Event Loop pattern. The host (Rust) manages infrastructure
|
|
//! (HTTP server, polling), while WASM modules define channel behavior through
|
|
//! callbacks.
|
|
//!
|
|
//! # Architecture
|
|
//!
|
|
//! ```text
|
|
//! ┌─────────────────────────────────────────────────────────────────────────────────┐
|
|
//! │ Host-Managed Event Loop │
|
|
//! │ │
|
|
//! │ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
//! │ │ HTTP │ │ Polling │ │ Timer │ │
|
|
//! │ │ Router │ │ Scheduler │ │ Scheduler │ │
|
|
//! │ └──────┬──────┘ └──────┬───────┘ └──────┬───────┘ │
|
|
//! │ │ │ │ │
|
|
//! │ └───────────────────┴────────────────────┘ │
|
|
//! │ │ │
|
|
//! │ ▼ │
|
|
//! │ ┌─────────────────┐ │
|
|
//! │ │ Event Router │ │
|
|
//! │ └────────┬────────┘ │
|
|
//! │ │ │
|
|
//! │ ┌──────────────────┼──────────────────┐ │
|
|
//! │ ▼ ▼ ▼ │
|
|
//! │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
|
//! │ │ on_http_req │ │ on_poll │ │ on_respond │ WASM Exports │
|
|
//! │ └─────────────┘ └─────────────┘ └─────────────┘ │
|
|
//! │ │ │ │ │
|
|
//! │ └──────────────────┴──────────────────┘ │
|
|
//! │ │ │
|
|
//! │ ▼ │
|
|
//! │ ┌─────────────────┐ │
|
|
//! │ │ Host Imports │ │
|
|
//! │ │ emit_message │──────────▶ MessageStream │
|
|
//! │ │ http_request │ │
|
|
//! │ │ log, etc. │ │
|
|
//! │ └─────────────────┘ │
|
|
//! └─────────────────────────────────────────────────────────────────────────────────┘
|
|
//! ```
|
|
//!
|
|
//! # Key Design Decisions
|
|
//!
|
|
//! 1. **Fresh Instance Per Callback** (NEAR Pattern) - Full isolation, no shared mutable state
|
|
//! 2. **Host Manages Infrastructure** - HTTP server, polling, timing in Rust
|
|
//! 3. **WASM Defines Behavior** - Callbacks for events, message parsing, response handling
|
|
//! 4. **Reuse Tool Runtime** - Share Wasmtime engine, extend capabilities
|
|
//!
|
|
//! # Security Model
|
|
//!
|
|
//! | Threat | Mitigation |
|
|
//! |--------|------------|
|
|
//! | Path hijacking | `allowed_paths` restricts registrable endpoints |
|
|
//! | Token exposure | Injected at host boundary, WASM never sees |
|
|
//! | State pollution | Fresh instance per callback |
|
|
//! | Workspace escape | Paths prefixed with `channels/<name>/` |
|
|
//! | Message spam | Rate limiting on `emit_message` |
|
|
//! | Resource exhaustion | Fuel metering, memory limits, callback timeout |
|
|
//! | Polling abuse | Minimum 30s interval enforced |
|
|
//!
|
|
//! # Example Usage
|
|
//!
|
|
//! ```ignore
|
|
//! use ironclaw::channels::wasm::{WasmChannelLoader, WasmChannelRuntime};
|
|
//!
|
|
//! // Create runtime (can share engine with tool runtime)
|
|
//! let runtime = WasmChannelRuntime::new(config)?;
|
|
//!
|
|
//! // Load channels from directory
|
|
//! let loader = WasmChannelLoader::new(runtime);
|
|
//! let channels = loader.load_from_dir(Path::new("~/.ironclaw/channels/")).await?;
|
|
//!
|
|
//! // Add to channel manager
|
|
//! for channel in channels {
|
|
//! manager.add(Box::new(channel));
|
|
//! }
|
|
//! ```
|
|
|
|
mod bundled;
|
|
mod capabilities;
|
|
mod error;
|
|
mod host;
|
|
mod loader;
|
|
mod router;
|
|
mod runtime;
|
|
mod schema;
|
|
pub(crate) mod signature;
|
|
#[allow(dead_code)]
|
|
pub(crate) mod storage;
|
|
mod wrapper;
|
|
|
|
// Core types
|
|
pub use bundled::{available_channel_names, bundled_channel_names, install_bundled_channel};
|
|
pub use capabilities::{ChannelCapabilities, EmitRateLimitConfig, HttpEndpointConfig, PollConfig};
|
|
pub use error::WasmChannelError;
|
|
pub use host::{ChannelEmitRateLimiter, ChannelHostState, EmittedMessage};
|
|
pub use loader::{
|
|
DiscoveredChannel, LoadResults, LoadedChannel, WasmChannelLoader, default_channels_dir,
|
|
discover_channels,
|
|
};
|
|
pub use router::{RegisteredEndpoint, WasmChannelRouter, create_wasm_channel_router};
|
|
pub use runtime::{PreparedChannelModule, WasmChannelRuntime, WasmChannelRuntimeConfig};
|
|
pub use schema::{
|
|
ChannelCapabilitiesFile, ChannelConfig, SecretSetupSchema, SetupSchema, WebhookSchema,
|
|
};
|
|
pub use wrapper::{HttpResponse, SharedWasmChannel, WasmChannel};
|