* Add an explicit native Wasm command plugin runtime * Document the plugin test workflow in English * Report plugin execution causes and explicit fuel budgets * Allow explicit user plugin resource ceilings * Document the persistent isolated plugin test profile * Require the Wasmtime 48.0.8 security fixes Raise the minimum native runtime version and update its locked Cranelift and Wasmtime dependencies for RUSTSEC-2026-0422, RUSTSEC-2026-0423 and RUSTSEC-2026-0424. Preserve the existing plugin resource defaults and approval flow. * claim: #1221 phase 1 * Plugins: share host contracts and reject unused network imports Split plugin manifests, permissions, limits, typed errors, entry schemas and the PluginHost trait into craft-plugin. Put the Wasmtime sandbox in craft-plugin-wasm, with no dependencies on SolidCraft crates and no WASI or network linker. SolidCraft supplies its command catalog and transactions, and the UI routes namespaced plugin calls through the existing worker. Inspect a component's imports before instantiating it (bounded). Refuse sockets, HTTP and fetch imports even when Wasmtime would elide an unused import. Keep net manifest requests forbidden and report typed errors. Exercise WAT components against a tiny independent app and SolidCraft. Cover file reads and writes without grants, swallowed denials, granted reads, runaway fuel exhaustion, traps and rollback, network refusal, read-only entries, exact approval and one-step undo/redo. Attribute the shared fixture. Checked: - cargo test -p craft-plugin-wasm: 11 passed - cargo test -p solidcraft-engine --features plugins plugin: 16 passed - cargo check -p solidcraft-ui-egui --all-targets: passed - cargo clippy -p craft-plugin -p craft-plugin-wasm -p solidcraft-engine --all-targets --features solidcraft-engine/plugins -- -D warnings: passed - cargo xtask layers: passed, 35 crates - cargo xtask lists: passed - cargo fmt -p craft-plugin -p craft-plugin-wasm -p solidcraft-engine -p solidcraft-ui-egui -p xtask -- --check: passed Full-suite and remaining platform checks are left to CI after push. Refs #1221, phase 1; design review remains required before phase 2. * Plugins: model.mesh is an export in the mesh-decisions check The plugin command hands a plugin a bounded copy of a body's display tessellation; it decides nothing about the model. It joins the check's list of display and export functions. * Cargo.lock: the plugin crates follow the workspace version (0.40.1) * Kernel cases: the plugin commands name where they are tested model.mesh, plugin.inspect, plugin.list and plugin.run take no kernel case (the folder takes no new ones); each EXEMPT line names the engine's plugin test file. * Plugins: enforce command authority, file scopes and per-run consent Stage granted file writes until successful execution and app commit. Check caller scopes for every file path and default command effects to edit. Preserve inspection identity, preflight complete scripts and clean up accepted sketch exits. Correct plugin schemas, preference drafts, fixture identifiers and runtime documentation. Add regressions in the existing engine, runtime, UI and CLI test files. Restore package-folder mismatch diagnostics and initialise consent-test catalogs. * Plugin tests: keep a test-only command out of the icon audit * Plugins: a link inside a granted folder is never followed File authorization looks at a path as the plugin spells it, so a visible symbolic link to a hidden folder (public -> .hidden) made public/secret.txt readable, and let staged writes land in the hidden folder, when no caller scope was set. Every file access now checks each part of the requested path inside the granted folder and refuses a link (or a Windows junction), for reads, writes and staged publication alike. A plugin cannot create links itself: it only writes new regular files. Test: a visible link to a hidden folder, and a file link to a hidden file, are refused for reads and writes, nothing is staged through them, and a plain file beside them still reads. * Show plugin entry fuel use in CLI debug logs * Plugin runtime README: links inside a granted folder are refused * Plugins: main's new operations-panel tests build the Answer job with no inspection main added two tests in control_job.rs that construct `Work::Answer` as a unit value; on this branch the variant carries `inspection`. * Designs keep plugin data under plugins/<plugin-id>/ untouched A design container reserves plugins/<plugin-id>/ for a plugin's own files (plugin_data, base64 by <plugin-id>/<path>, in a plain JSON design). They are kept and saved back byte for byte whether or not the plugin is installed, and opening a design never needs a plugin. One pending format file; the io design tests cover save/open with the namespace and without the plugin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Plugins 0.1.0: craft:plugin@0.1.0, manifest capabilities, every MCP command - The WIT package is craft:plugin@0.1.0; today's surface is the commands@0.1 capability (engine -> commands, exported command -> entry). ui, viewport, formats and storage arrive later as their own versioned interfaces; 0.x may break between minors. - plugin.json lists "capabilities": ["commands@0.1"] instead of runtime.api. The host refuses an unknown or newer capability at load with a typed, plain message ("needs commands 0.2; update SolidCraft or the plugin"), and a component importing another interface version before instantiation. - The hard-coded command allowlist is gone: every command in the MCP catalog can be listed. Sensitive groups (file, doc, app, plugin) are refused unless the manifest requests them in permissions.command_groups and the user grants them; a granted file or doc command sees only the granted folders. - Remove the stray REVIEW_REPORT.md; update docs and the test guide. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Plugins 0.1.0: cargo fmt --------- Co-authored-by: kenos <crono2srv@gmail.com> Co-authored-by: Brennen Herbruck <brennen.herbruck@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
craft-plugin
App-independent contracts for one-shot plugins in Craft apps. Commands and schemas are JSON data supplied by the app. This crate has no SolidCraft or CAD dependency and runs no plugin code.
Public API
| Item | Purpose |
|---|---|
PluginHost |
App command catalog and execution, transactions, file authorization, logging, progress and cancellation |
CommandSchema, Effect |
Command input/output schemas and read/edit effects |
Manifest, RuntimeManifest, Entry, UiSlot |
Package metadata, executable entries, declared inputs and placement preferences |
parse_manifest, valid_id |
Bounded parsing and validation; package ids must match folder names |
Permissions, FilePermission, FileGrant |
Requested capabilities and separately approved named folders |
Limits, HostLimits |
Invocation budgets and user ceilings; HostLimits::check compares them |
HostError, Result |
Typed permission, command, limit, manifest, input, trap and cancellation failures |
API, WIT, MAX_* |
Interface identifier, WIT text and size/address-space limits |
The app implements PluginHost and defines command policy, approval and transaction history.
authorize_file_path applies caller scope to each complete file path, in addition to folder
grants. Its default denies hidden child names unless a more specific approved folder grant
covers them; an app may override it to enforce its explicit scope policy.
The WIT declares craft:plugin@0.1.0, world command-plugin: the
capability commands@0.1 (CAPABILITIES). A manifest lists the capabilities it needs
("capabilities": ["commands@0.1"]); check_capabilities refuses an unknown or newer one with
HostError::UnsupportedCapability. While a version is 0.x, minors may break each other.
The Wasm runtime begins an app transaction and requests
commit or rollback after guest execution. It stages granted file writes until the guest
succeeds and the app commits. File publication after app commit is not atomic across
multiple targets; a publication failure can leave files changed. These contracts do not
promise atomic rollback of all external effects.
Limits and permissions
Invocation defaults are 10,000,000 fuel, 64 MiB memory and a 5000 ms deadline.
HostLimits defaults to 100,000,000,000 fuel and 128 MiB. Callers must check requested
budgets against their ceilings before execution. Fuel must be positive, memory is
1..4096 MiB and the deadline is 1..30000 ms. Manifests are capped at 16 KiB.
Commands are exact ids, intersected with the app catalog. A catalog command may carry a
sensitive group; the guest calls it only when permissions.command_groups requests the
group and PluginHost::granted_command_groups grants it. Folder requests alone grant
nothing: the app supplies matching FileGrant values. Clock permission allows wall time;
without it, the runtime returns a fixed epoch. Requests for net are refused.
Parsing a manifest neither approves nor executes its component. These contracts have no
native execution requirement.
Validation
From the repository root, cargo test -p craft-plugin exercises manifests, permissions,
entries and limits. cargo xtask shared checks extraction and tests an isolated workspace.
See the runtime reference for the SolidCraft adapter policy.