act-cli 0.8.1__tar.gz → 0.8.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {act_cli-0.8.1 → act_cli-0.8.2}/Cargo.lock +9 -2
- {act_cli-0.8.1 → act_cli-0.8.2}/Cargo.toml +1 -1
- {act_cli-0.8.1 → act_cli-0.8.2}/PKG-INFO +1 -1
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/Cargo.toml +1 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/main.rs +42 -1
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/runtime/mod.rs +19 -3
- {act_cli-0.8.1 → act_cli-0.8.2}/README.md +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/README.md +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/build.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/config.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/format.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/http.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/resolve.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/rmcp_bridge.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/runtime/bindings/mod.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/runtime/effective.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/runtime/fs_matcher.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/runtime/fs_policy.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/runtime/http_client.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/runtime/http_policy.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/runtime/network.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/runtime/sessions.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/src/runtime/sockets_policy.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/wit/deps/act-core/act-core.wit +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/wit/deps/act-tools/act-tools.wit +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/wit/deps.lock +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/wit/deps.toml +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/act-cli/wit/world.wit +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/crates/act-store/Cargo.toml +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/crates/act-store/README.md +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/crates/act-store/src/fetch.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/crates/act-store/src/index.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/crates/act-store/src/layout.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/crates/act-store/src/lib.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/crates/act-store/src/lock.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/crates/act-store/src/provenance.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/crates/act-store/src/reference.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/crates/act-store/src/referrer.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/crates/act-store/src/store.rs +0 -0
- {act_cli-0.8.1 → act_cli-0.8.2}/pyproject.toml +0 -0
|
@@ -4,7 +4,7 @@ version = 4
|
|
|
4
4
|
|
|
5
5
|
[[package]]
|
|
6
6
|
name = "act-build"
|
|
7
|
-
version = "0.8.
|
|
7
|
+
version = "0.8.2"
|
|
8
8
|
dependencies = [
|
|
9
9
|
"act-types",
|
|
10
10
|
"anyhow",
|
|
@@ -37,7 +37,7 @@ dependencies = [
|
|
|
37
37
|
|
|
38
38
|
[[package]]
|
|
39
39
|
name = "act-cli"
|
|
40
|
-
version = "0.8.
|
|
40
|
+
version = "0.8.2"
|
|
41
41
|
dependencies = [
|
|
42
42
|
"act-store",
|
|
43
43
|
"act-types",
|
|
@@ -45,6 +45,7 @@ dependencies = [
|
|
|
45
45
|
"axum",
|
|
46
46
|
"base64",
|
|
47
47
|
"bytes",
|
|
48
|
+
"bytesize",
|
|
48
49
|
"ciborium",
|
|
49
50
|
"cidr",
|
|
50
51
|
"clap",
|
|
@@ -384,6 +385,12 @@ version = "1.11.1"
|
|
|
384
385
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
385
386
|
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
|
386
387
|
|
|
388
|
+
[[package]]
|
|
389
|
+
name = "bytesize"
|
|
390
|
+
version = "2.3.1"
|
|
391
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
392
|
+
checksum = "6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3"
|
|
393
|
+
|
|
387
394
|
[[package]]
|
|
388
395
|
name = "cap-fs-ext"
|
|
389
396
|
version = "3.4.5"
|
|
@@ -55,6 +55,12 @@ struct CommonOpts {
|
|
|
55
55
|
#[arg(long = "deny-socket")]
|
|
56
56
|
sockets_deny: Vec<String>,
|
|
57
57
|
|
|
58
|
+
/// Cap the component's wasm linear memory. Accepts a byte count or a size
|
|
59
|
+
/// with a unit — binary (`512MiB`) or decimal (`512MB`). Growth past the cap
|
|
60
|
+
/// fails inside the guest instead of ballooning the host process.
|
|
61
|
+
#[arg(long = "max-memory", value_parser = parse_max_memory)]
|
|
62
|
+
max_memory: Option<usize>,
|
|
63
|
+
|
|
58
64
|
/// Use a named profile from the config file
|
|
59
65
|
#[arg(long)]
|
|
60
66
|
profile: Option<String>,
|
|
@@ -318,6 +324,22 @@ fn parse_cli_metadata(
|
|
|
318
324
|
}
|
|
319
325
|
}
|
|
320
326
|
|
|
327
|
+
/// Parse a `--max-memory` value via the `bytesize` crate: a byte count or a
|
|
328
|
+
/// size with a unit, decimal (`512MB` = 512·10⁶) or binary (`512MiB` = 512·2²⁰).
|
|
329
|
+
fn parse_max_memory(s: &str) -> Result<usize, String> {
|
|
330
|
+
let bytes = s
|
|
331
|
+
.trim()
|
|
332
|
+
.parse::<bytesize::ByteSize>()
|
|
333
|
+
.map_err(|e| format!("invalid --max-memory value '{s}': {e}"))?
|
|
334
|
+
.as_u64();
|
|
335
|
+
let bytes =
|
|
336
|
+
usize::try_from(bytes).map_err(|_| format!("--max-memory value too large: '{s}'"))?;
|
|
337
|
+
if bytes == 0 {
|
|
338
|
+
return Err(format!("--max-memory must be greater than 0: '{s}'"));
|
|
339
|
+
}
|
|
340
|
+
Ok(bytes)
|
|
341
|
+
}
|
|
342
|
+
|
|
321
343
|
struct ResolvedOpts {
|
|
322
344
|
#[allow(dead_code)]
|
|
323
345
|
config_file: config::ConfigFile,
|
|
@@ -325,6 +347,7 @@ struct ResolvedOpts {
|
|
|
325
347
|
http: config::HttpConfig,
|
|
326
348
|
sockets: config::SocketsConfig,
|
|
327
349
|
metadata: Option<serde_json::Value>,
|
|
350
|
+
max_memory: Option<usize>,
|
|
328
351
|
}
|
|
329
352
|
|
|
330
353
|
fn resolve_opts(opts: &CommonOpts) -> Result<ResolvedOpts> {
|
|
@@ -360,6 +383,7 @@ fn resolve_opts(opts: &CommonOpts) -> Result<ResolvedOpts> {
|
|
|
360
383
|
http,
|
|
361
384
|
sockets,
|
|
362
385
|
metadata,
|
|
386
|
+
max_memory: opts.max_memory,
|
|
363
387
|
})
|
|
364
388
|
}
|
|
365
389
|
|
|
@@ -388,6 +412,7 @@ async fn prepare_component(
|
|
|
388
412
|
let fs = resolved.fs;
|
|
389
413
|
let http = resolved.http;
|
|
390
414
|
let sockets = resolved.sockets;
|
|
415
|
+
let max_memory = resolved.max_memory;
|
|
391
416
|
|
|
392
417
|
let mut preopens = runtime::fs_policy::derive_preopens(&fs);
|
|
393
418
|
let mount_root = info.std.capabilities.fs_mount_root().unwrap_or("/");
|
|
@@ -410,7 +435,7 @@ async fn prepare_component(
|
|
|
410
435
|
let wasm = runtime::load_component(&engine, &component_path)?;
|
|
411
436
|
let linker = runtime::create_linker(&engine)?;
|
|
412
437
|
let (instance, session_provider, store) = runtime::instantiate_component(
|
|
413
|
-
&engine, &wasm, &linker, &preopens, &http, &fs, &sockets, &info,
|
|
438
|
+
&engine, &wasm, &linker, &preopens, &http, &fs, &sockets, &info, max_memory,
|
|
414
439
|
)
|
|
415
440
|
.await?;
|
|
416
441
|
let has_sessions = session_provider.is_some();
|
|
@@ -969,6 +994,22 @@ mod tests {
|
|
|
969
994
|
assert_eq!(result, Some(serde_json::json!({"key": "value"})));
|
|
970
995
|
}
|
|
971
996
|
|
|
997
|
+
#[test]
|
|
998
|
+
fn parse_max_memory_units_and_bytes() {
|
|
999
|
+
assert_eq!(parse_max_memory("268435456").unwrap(), 256 << 20); // bare = bytes
|
|
1000
|
+
assert_eq!(parse_max_memory("256MiB").unwrap(), 256 << 20); // binary
|
|
1001
|
+
assert_eq!(parse_max_memory("1GiB").unwrap(), 1 << 30);
|
|
1002
|
+
assert_eq!(parse_max_memory("512KiB").unwrap(), 512 << 10);
|
|
1003
|
+
assert_eq!(parse_max_memory("256MB").unwrap(), 256_000_000); // decimal
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
#[test]
|
|
1007
|
+
fn parse_max_memory_rejects_garbage_and_zero() {
|
|
1008
|
+
assert!(parse_max_memory("12xyz").is_err());
|
|
1009
|
+
assert!(parse_max_memory("").is_err());
|
|
1010
|
+
assert!(parse_max_memory("0").is_err());
|
|
1011
|
+
}
|
|
1012
|
+
|
|
972
1013
|
#[test]
|
|
973
1014
|
fn parse_cli_metadata_from_file() {
|
|
974
1015
|
let mut file = NamedTempFile::new().unwrap();
|
|
@@ -5,7 +5,9 @@ use std::pin::Pin;
|
|
|
5
5
|
use std::task::{Context, Poll};
|
|
6
6
|
use tokio::sync::{mpsc, oneshot};
|
|
7
7
|
use wasmtime::component::{Component, Linker, ResourceTable, Source, StreamConsumer, StreamResult};
|
|
8
|
-
use wasmtime::{
|
|
8
|
+
use wasmtime::{
|
|
9
|
+
AsContextMut, Config, Engine, Store, StoreContextMut, StoreLimits, StoreLimitsBuilder,
|
|
10
|
+
};
|
|
9
11
|
use wasmtime_wasi::{WasiCtx, WasiCtxBuilder, WasiCtxView, WasiView};
|
|
10
12
|
use wasmtime_wasi_http::WasiHttpCtx;
|
|
11
13
|
use wasmtime_wasi_http::p3::WasiHttpCtxView;
|
|
@@ -36,6 +38,9 @@ pub struct HostState {
|
|
|
36
38
|
fs_matcher: crate::runtime::fs_matcher::FsMatcher,
|
|
37
39
|
fs_mode: crate::config::PolicyMode,
|
|
38
40
|
fd_paths: crate::runtime::fs_policy::FdPathMap,
|
|
41
|
+
/// Caps the component's wasm linear memory growth (via `store.limiter`).
|
|
42
|
+
/// Default `StoreLimits` is unlimited.
|
|
43
|
+
limits: StoreLimits,
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
impl HostState {
|
|
@@ -153,6 +158,7 @@ pub async fn create_store(
|
|
|
153
158
|
fs: &crate::config::FsConfig,
|
|
154
159
|
sockets: &crate::config::SocketsConfig,
|
|
155
160
|
info: &ComponentInfo,
|
|
161
|
+
max_memory: Option<usize>,
|
|
156
162
|
) -> Result<Store<HostState>> {
|
|
157
163
|
// Intersect user policy with the component's declared capabilities.
|
|
158
164
|
let effective_fs = crate::runtime::effective::effective_fs(fs, &info.std.capabilities).config;
|
|
@@ -208,8 +214,17 @@ pub async fn create_store(
|
|
|
208
214
|
preopens: preopen_pairs,
|
|
209
215
|
by_rep: Default::default(),
|
|
210
216
|
},
|
|
217
|
+
limits: match max_memory {
|
|
218
|
+
Some(bytes) => StoreLimitsBuilder::new().memory_size(bytes).build(),
|
|
219
|
+
None => StoreLimits::default(),
|
|
220
|
+
},
|
|
211
221
|
};
|
|
212
|
-
|
|
222
|
+
let mut store = Store::new(engine, state);
|
|
223
|
+
// Enforce the linear-memory cap: when the guest grows memory past the limit,
|
|
224
|
+
// `memory.grow` fails (the guest typically traps OOM) instead of letting the
|
|
225
|
+
// host process balloon. No-op when `max_memory` is None (default limits).
|
|
226
|
+
store.limiter(|state| &mut state.limits);
|
|
227
|
+
Ok(store)
|
|
213
228
|
}
|
|
214
229
|
|
|
215
230
|
// ── Component info from custom section ──
|
|
@@ -346,12 +361,13 @@ pub async fn instantiate_component(
|
|
|
346
361
|
fs: &crate::config::FsConfig,
|
|
347
362
|
sockets: &crate::config::SocketsConfig,
|
|
348
363
|
info: &ComponentInfo,
|
|
364
|
+
max_memory: Option<usize>,
|
|
349
365
|
) -> Result<(
|
|
350
366
|
ActWorld,
|
|
351
367
|
Option<sessions::SessionProvider>,
|
|
352
368
|
Store<HostState>,
|
|
353
369
|
)> {
|
|
354
|
-
let mut store = create_store(engine, preopens, http, fs, sockets, info).await?;
|
|
370
|
+
let mut store = create_store(engine, preopens, http, fs, sockets, info, max_memory).await?;
|
|
355
371
|
|
|
356
372
|
// Manual instantiation flow (replicates ActWorld::instantiate_async)
|
|
357
373
|
// so we keep access to the raw `Instance` for session-provider lookup.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|