diff --git a/crates/basal-core/src/templates.rs b/crates/basal-core/src/templates.rs index c81f8988..45358adc 100644 --- a/crates/basal-core/src/templates.rs +++ b/crates/basal-core/src/templates.rs @@ -387,8 +387,7 @@ pub fn validate_values(manifest: &Manifest, values: &Value, now: i64) -> Result< value.as_str().and_then(resolved_path).is_some_and(|real| { let inside = under .iter() - .filter_map(|root| basal_host::builtins::expand_home(root)) - .filter_map(|root| std::fs::canonicalize(root).ok()) + .filter_map(|root| basal_host::builtins::canonical_root(root)) .any(|root| real.starts_with(root)); if let Some(text) = real.to_str() { canonical = Value::String(text.into()); @@ -463,8 +462,7 @@ pub fn grant_guards( let root = values[&name].as_str().expect("validated path").to_owned(); let under = under .iter() - .filter_map(|r| basal_host::builtins::expand_home(r)) - .filter_map(|r| std::fs::canonicalize(r).ok()) + .filter_map(|r| basal_host::builtins::canonical_root(r)) .filter_map(|r| r.to_str().map(str::to_owned)) .collect(); Some(basal_host::builtins::TemplateRoot { diff --git a/crates/basal-core/tests/templates.rs b/crates/basal-core/tests/templates.rs index e34b6614..c80614e2 100644 --- a/crates/basal-core/tests/templates.rs +++ b/crates/basal-core/tests/templates.rs @@ -10,6 +10,16 @@ fn base() -> Value { fn parse(value: &Value) -> Result { Manifest::parse(&value.to_string()) } +/// An absolute root as a manifest on this platform spells it: on Windows, +/// roots are drive paths. +#[cfg(unix)] +const TMP: &str = "/tmp"; +#[cfg(windows)] +const TMP: &str = r"C:\tmp"; +/// `TMP` joined with one more component, spelled for this platform. +fn under_tmp(name: &str) -> String { + format!("{TMP}{}{name}", std::path::MAIN_SEPARATOR) +} fn with_parameter(decl: Value) -> Value { let mut m = base(); m["params"] = json!({"value":decl}); @@ -55,7 +65,7 @@ fn all_parameter_declarations_require_closed_valid_bounds() { json!({"type":"enum","values":[]}), json!({"type":"enum","values":(0..33).map(|n|format!("v{n}")).collect::>()}), json!({"type":"enum","values":["v","v"]}), - json!({"type":"path","under":["/tmp","/tmp"]}), + json!({"type":"path","under":[TMP,TMP]}), json!({"type":"url","hosts":["example.com","example.com"]}), json!({"type":"timestamp","max_ahead":"forever"}), json!({"type":"unknown"}), @@ -139,7 +149,7 @@ fn template_limits_and_lifetime_are_bounded_and_required() { #[test] fn placeholders_must_occupy_whole_strings_in_typed_slots_only() { - let mut m = with_parameter(json!({"type":"path","under":["/tmp"]})); + let mut m = with_parameter(json!({"type":"path","under":[TMP]})); for field in ["purpose", "placement"] { m[field] = json!("$params.value"); assert!( @@ -167,11 +177,11 @@ fn placeholders_must_occupy_whole_strings_in_typed_slots_only() { json!({"fs":{"read":["$params.value"]}}), ), ( - json!({"type":"path","under":["/tmp"]}), + json!({"type":"path","under":[TMP]}), json!({"git":{"read":["$params.value"]}}), ), ( - json!({"type":"repo","under":["/tmp"]}), + json!({"type":"repo","under":[TMP]}), json!({"fs":{"write":["$params.value"]}}), ), ( @@ -288,19 +298,20 @@ fn parameter_failures_are_reported_in_name_order_with_bounds() { #[test] fn effective_manifest_narrows_every_allowed_slot_and_preserves_static_grants() { let mut m = base(); - m["params"] = json!({"path":{"type":"path","under":["/tmp"]},"repo":{"type":"repo","under":["/tmp"]},"url":{"type":"url","hosts":["example.com"]},"interval":{"type":"duration","min":"1m","max":"1h"}}); - m["fs"] = json!({"read":["$params.path","/tmp"],"write":["$params.path"]}); + m["params"] = json!({"path":{"type":"path","under":[TMP]},"repo":{"type":"repo","under":[TMP]},"url":{"type":"url","hosts":["example.com"]},"interval":{"type":"duration","min":"1m","max":"1h"}}); + m["fs"] = json!({"read":["$params.path",TMP],"write":["$params.path"]}); m["git"] = json!({"read":["$params.repo"]}); m["net"] = json!({"fetch":[{"host":"$params.url"}]}); m["trigger"]["schedule"]["interval"] = json!("$params.interval"); let mut m = parse(&m).unwrap(); + let (file, repo) = (under_tmp("file"), under_tmp("repo")); effective( &mut m, - &json!({"path":"/tmp/file","repo":"/tmp/repo","url":"https://example.com/only","interval":"2m"}), + &json!({"path":file,"repo":repo,"url":"https://example.com/only","interval":"2m"}), ); - assert_eq!(m.fs.as_ref().unwrap().read, vec!["/tmp/file", "/tmp"]); - assert_eq!(m.fs.unwrap().write, vec!["/tmp/file"]); - assert_eq!(m.git.unwrap().read, vec!["/tmp/repo"]); + assert_eq!(m.fs.as_ref().unwrap().read, vec![file.as_str(), TMP]); + assert_eq!(m.fs.unwrap().write, vec![file]); + assert_eq!(m.git.unwrap().read, vec![repo]); assert_eq!(m.net.unwrap().fetch[0].host, "example.com"); assert_eq!(m.trigger.schedule.unwrap().interval.as_deref(), Some("2m")); } diff --git a/crates/basal-host/src/builtins/fs/windows.rs b/crates/basal-host/src/builtins/fs/windows.rs index c24c7cb7..ab730b69 100644 --- a/crates/basal-host/src/builtins/fs/windows.rs +++ b/crates/basal-host/src/builtins/fs/windows.rs @@ -1007,7 +1007,7 @@ fn process_profile_directory() -> Result { } #[cfg(windows)] -fn expand_root(root: &str) -> Result, Denial> { +pub(crate) fn expand_root(root: &str) -> Result, Denial> { let suffix = if root == "~" { "" } else if let Some(suffix) = root.strip_prefix("~/") { diff --git a/crates/basal-host/src/builtins/mod.rs b/crates/basal-host/src/builtins/mod.rs index edb643f0..ecd96154 100644 --- a/crates/basal-host/src/builtins/mod.rs +++ b/crates/basal-host/src/builtins/mod.rs @@ -211,6 +211,8 @@ impl Grant { /// Resolve symlinks component by component, including the deepest existing /// ancestor of a future path. A dangling symlink is not a future directory. +/// The result is spelled as the `fs` and `git` built-ins accept a root +/// ([`plain_spelling`]). pub fn resolved_path(text: &str) -> Option { use std::path::Component; let path = expand_home(text)?; @@ -218,6 +220,10 @@ pub fn resolved_path(text: &str) -> Option { for component in path.components() { match component { Component::CurDir => continue, + // A Windows drive (`C:`) on its own names that drive's current + // directory, so it is resolved together with the root that + // follows it in an absolute path. + Component::Prefix(prefix) => resolved.push(prefix.as_os_str()), Component::ParentDir => { resolved.pop(); } @@ -233,7 +239,35 @@ pub fn resolved_path(text: &str) -> Option { } } } - resolved.is_absolute().then_some(resolved) + if !resolved.is_absolute() { + return None; + } + plain_spelling(resolved) +} + +/// An existing root with `~` expanded and every symlink resolved, spelled as +/// the `fs` and `git` built-ins accept a root ([`plain_spelling`]). `None` +/// when it is not absolute or cannot be resolved. +pub fn canonical_root(text: &str) -> Option { + plain_spelling(std::fs::canonicalize(expand_home(text)?).ok()?) +} + +/// A resolved path as the built-ins spell it. On Windows, +/// `std::fs::canonicalize` returns an extended-length `\\?\X:\...` path, +/// which the Windows `fs` and `git` built-ins refuse; this drops that +/// prefix and accepts only a drive path whose spelling the Windows `fs` +/// built-in accepts. Elsewhere the path is returned unchanged. +#[cfg(not(windows))] +fn plain_spelling(path: PathBuf) -> Option { + Some(path) +} + +#[cfg(windows)] +fn plain_spelling(path: PathBuf) -> Option { + let text = path.to_str()?; + let plain = text.strip_prefix(r"\\?\").unwrap_or(text); + fs::windows::validate_raw_spelling(plain).ok()?; + Some(PathBuf::from(plain)) } /// Whether `kind` is a file, git or network built-in. @@ -286,7 +320,18 @@ pub fn envelope(args: &Value, grant: &Grant) -> Value { /// Expands a leading `~` to `$HOME`. Returns `None` for a path that is not /// absolute after expansion, or when `$HOME` is unset or relative. +/// +/// On Windows `~` is the profile folder of the process token, the folder +/// the Windows `fs` built-in expands a `~` root to, never an environment +/// variable; `None` when that profile is unavailable or the expanded path +/// is not a drive path the `fs` built-in accepts. pub fn expand_home(text: &str) -> Option { + #[cfg(windows)] + if text == "~" || text.starts_with("~/") { + return fs::windows::expand_root(text) + .ok() + .map(|path| PathBuf::from(path.into_owned())); + } let home = || { std::env::var_os("HOME") .map(PathBuf::from) diff --git a/crates/basal-module/tests/common/mod.rs b/crates/basal-module/tests/common/mod.rs index 7e78722b..325390cb 100644 --- a/crates/basal-module/tests/common/mod.rs +++ b/crates/basal-module/tests/common/mod.rs @@ -71,6 +71,19 @@ pub fn scratch(tag: &str) -> PathBuf { dir } +/// The real path of an existing `path`, spelled as a manifest root. On +/// Windows `std::fs::canonicalize` adds the extended-length `\\?\` prefix, +/// which manifest roots and the `fs` and `git` built-ins refuse, so it is +/// removed here. +pub fn canonical(path: &std::path::Path) -> PathBuf { + let real = std::fs::canonicalize(path).expect("canonical path"); + #[cfg(windows)] + if let Some(plain) = real.to_str().and_then(|text| text.strip_prefix(r"\\?\")) { + return PathBuf::from(plain); + } + real +} + pub struct Options { pub hosts: Option, pub worker_binary: Option, diff --git a/crates/basal-module/tests/flow_templates.rs b/crates/basal-module/tests/flow_templates.rs index b5efb8e2..b7b4a1d7 100644 --- a/crates/basal-module/tests/flow_templates.rs +++ b/crates/basal-module/tests/flow_templates.rs @@ -169,7 +169,7 @@ impl WorkDirectory { NEXT.fetch_add(1, Ordering::Relaxed) )); std::fs::create_dir(&path).unwrap(); - Self(std::fs::canonicalize(path).unwrap()) + Self(common::canonical(&path)) } } impl Drop for WorkDirectory { diff --git a/crates/basal-module/tests/templates.rs b/crates/basal-module/tests/templates.rs index f04b7418..ad34ab58 100644 --- a/crates/basal-module/tests/templates.rs +++ b/crates/basal-module/tests/templates.rs @@ -801,7 +801,7 @@ fn activation_uses_effective_grants_and_journaled_self_and_params() { let target = f.dir.join("target"); std::fs::write(&target, "watched").unwrap(); std::fs::write(f.dir.join("neighbor"), "private").unwrap(); - let root = std::fs::canonicalize(&f.dir).unwrap(); + let root = common::canonical(&f.dir); let mut m = manifest(); m["params"]["path"] = json!({"type":"path","under":[root]}); m["fs"] = json!({"read":["$params.path"]}); @@ -1303,7 +1303,7 @@ fn template_dry_run_uses_canonical_values_effective_grants_and_capture() { let target = f.dir.join("target"); std::fs::write(&target, "watched").unwrap(); std::fs::write(f.dir.join("neighbor"), "private").unwrap(); - let root = std::fs::canonicalize(&f.dir).unwrap(); + let root = common::canonical(&f.dir); let mut m = manifest(); m["params"]["path"] = json!({"type":"path","under":[root]}); m["fs"] = json!({"read":["$params.path"]}); @@ -1569,7 +1569,7 @@ fn instance_dry_run_uses_bound_values_owner_grants_and_approved_version() { let f = setup("instance-dry-bound", true); let target = f.dir.join("target"); std::fs::write(&target, "bound").unwrap(); - let root = std::fs::canonicalize(&f.dir).unwrap(); + let root = common::canonical(&f.dir); let mut m = manifest(); m["params"]["path"] = json!({"type":"path","under":[root]}); m["fs"] = json!({"read":["$params.path"]}); diff --git a/mutations.d/core-events-templates.toml b/mutations.d/core-events-templates.toml index 83b1af01..7b6b9af1 100644 --- a/mutations.d/core-events-templates.toml +++ b/mutations.d/core-events-templates.toml @@ -121,7 +121,7 @@ runner = "cargo" package = "basal-core" platforms = ["linux"] target = "--lib" -expect_red = ["events::tests::body_is_journaled_before_script_and_replay_never_calls_live"] +expect_red = ["events::tests::body_is_journaled_before_script_and_replay_never_calls_live", "events::tests::journaled_flow_targeted_body_is_checked_against_run"] only = true build_timeout_s = 3600 timeout_s = 600 @@ -293,7 +293,7 @@ runner = "cargo" package = "basal-core" platforms = ["linux"] target = "--test templates" -expect_red = ["placeholders_must_occupy_whole_strings_in_typed_slots_only"] +expect_red = ["placeholders_must_occupy_whole_strings_in_typed_slots_only", "one_shot_requires_timestamp_placeholder_and_once_policy"] only = true file = "crates/basal-core/src/templates.rs" old = "if !fits {\n return Err(placeholder(field));" @@ -321,7 +321,7 @@ runner = "cargo" package = "basal-core" platforms = ["linux"] target = "--test templates" -expect_red = ["scalar_values_keep_spelling_and_enforce_types_and_bounds"] +expect_red = ["scalar_values_keep_spelling_and_enforce_types_and_bounds", "integer_bounds_and_values_remain_exact_script_numbers", "parameter_failures_are_reported_in_name_order_with_bounds", "timestamps_normalize_utc_milliseconds_and_reject_finer_precision"] only = true file = "crates/basal-core/src/templates.rs" old = "if !fits {\n return Err(parameter_refusal(\"param_out_of_bounds\", name, bound));" @@ -363,11 +363,11 @@ runner = "cargo" package = "basal-module" platforms = ["linux"] target = "--test templates" -expect_red = ["path_and_repo_values_resolve_symlinks_and_future_ancestors_before_bounds"] +expect_red = ["path_and_repo_values_resolve_symlinks_and_future_ancestors_before_bounds", "template_dry_run_path_and_repo_canonicalization_and_bounds_match_instances"] only = true file = "crates/basal-core/src/templates.rs" old = "inside && (!matches!(decl, Parameter::Repo { .. }) || is_repository(&real))" -new = "true /* NON-VACUITY BREAK */" +new = "(inside || true) /* NON-VACUITY BREAK */ && (!matches!(decl, Parameter::Repo { .. }) || is_repository(&real))" [[control]] id = "template-expiry-admission" @@ -451,7 +451,7 @@ expect_red = ["idempotent_creation_moves_version_extends_never_shortens_and_keep only = true file = "crates/basal-core/src/templates.rs" old = "unwrap_or(expires_at).max(expires_at)" -new = "unwrap_or(expires_at).min(expires_at) /* NON-VACUITY BREAK */" +new = "unwrap_or(expires_at).max(expires_at).min(expires_at) /* NON-VACUITY BREAK */" [[control]] id = "template-one-shot-ends" @@ -461,7 +461,7 @@ runner = "cargo" package = "basal-module" platforms = ["linux"] target = "--test templates" -expect_red = ["one_shot_fires_once_after_downtime_and_ends_on_success_failure_or_cancel"] +expect_red = ["one_shot_fires_once_after_downtime_and_ends_on_success_failure_or_cancel", "a_template_run_ends_only_itself_after_finishing_even_when_it_fails"] only = true file = "crates/basal-core/src/templates.rs" old = "end(tx, &flow, at)?;" @@ -657,8 +657,9 @@ runner = "cargo" package = "basal-module" platforms = ["linux"] target = "--test templates" -expect_red = ["template_dry_run_bounds_preserve_integer_and_timestamp_rules"] +expect_red = ["template_dry_run_bounds_preserve_integer_and_timestamp_rules", "template_dry_run_path_and_repo_canonicalization_and_bounds_match_instances"] only = true +select = { filter = "template_dry_run_" } file = "crates/basal-core/src/templates.rs" old = """ }; if !fits {""" diff --git a/mutations.d/core-runtime.toml b/mutations.d/core-runtime.toml index 5a06dc31..cb768998 100644 --- a/mutations.d/core-runtime.toml +++ b/mutations.d/core-runtime.toml @@ -1261,7 +1261,7 @@ runner = "cargo" package = "basal-module" platforms = ["linux"] target = "--test event_preamble" -expect_red = ["worker_preamble_supplies_verified_json_and_synthetic_capture_calls_nothing_live"] +expect_red = ["worker_preamble_supplies_verified_json_and_synthetic_capture_calls_nothing_live", "delivered_body_flow_mismatch_fails_run_before_script"] only = true build_timeout_s = 3600 timeout_s = 600 @@ -1421,7 +1421,7 @@ runner = "cargo" package = "basal-module" platforms = ["linux"] target = "--test templates" -expect_red = ["activation_uses_effective_grants_and_journaled_self_and_params"] +expect_red = ["activation_uses_effective_grants_and_journaled_self_and_params", "instance_dry_run_uses_bound_values_owner_grants_and_approved_version", "one_shot_fires_once_after_downtime_and_ends_on_success_failure_or_cancel", "template_dry_run_at_fires_once_immediately_with_canonical_timestamp", "template_dry_run_creates_no_rows_and_uses_no_quota", "template_dry_run_path_and_repo_canonicalization_and_bounds_match_instances", "template_dry_run_uses_canonical_values_effective_grants_and_capture", "template_stat_of_a_missing_target_reports_absence_then_appearance"] only = true file = "crates/basal-core/src/driver.rs" old = "params_input: self.run.params_input.clone()," diff --git a/mutations.d/host-builtins.toml b/mutations.d/host-builtins.toml index 48795615..b75b2d17 100644 --- a/mutations.d/host-builtins.toml +++ b/mutations.d/host-builtins.toml @@ -988,7 +988,7 @@ runner = "cargo" package = "basal-module" platforms = ["linux"] target = "--test templates" -expect_red = ["template_stat_of_a_missing_target_reports_absence_then_appearance"] +expect_red = ["template_stat_of_a_missing_target_reports_absence_then_appearance", "missing_stat_with_an_escaped_ancestor_is_refused_not_reported_absent"] only = true file = "crates/basal-host/src/builtins/mod.rs" old = 'return Some(json!({"exists":false}));' diff --git a/mutations.d/host-routing.toml b/mutations.d/host-routing.toml index 1b481603..e7894bc5 100644 --- a/mutations.d/host-routing.toml +++ b/mutations.d/host-routing.toml @@ -1389,7 +1389,7 @@ runner = "cargo" package = "basal-module" platforms = ["macos"] target = "--test hosts" -expect_red = ["digest_status_tag_is_top_level_and_absence_preserves_wire_bytes"] +expect_red = ["digest_status_tag_is_top_level_and_absence_preserves_wire_bytes", "journaled_sink_intent_is_byte_identical_after_a_cut"] only = true build_timeout_s = 3600 timeout_s = 600 @@ -1405,7 +1405,7 @@ runner = "cargo" package = "basal-module" platforms = ["macos"] target = "--test hosts" -expect_red = ["digest_status_tag_is_top_level_and_absence_preserves_wire_bytes"] +expect_red = ["digest_status_tag_is_top_level_and_absence_preserves_wire_bytes", "core_requests_match_c3_c4_field_for_field"] only = true build_timeout_s = 3600 timeout_s = 600 diff --git a/mutations.d/module.toml b/mutations.d/module.toml index 6a2c8738..28b200ad 100644 --- a/mutations.d/module.toml +++ b/mutations.d/module.toml @@ -2295,7 +2295,7 @@ runner = "cargo" package = "basal-module" platforms = ["linux"] target = "--test templates" -expect_red = ["template_dry_run_uses_canonical_values_effective_grants_and_capture"] +expect_red = ["template_dry_run_uses_canonical_values_effective_grants_and_capture", "instance_dry_run_uses_bound_values_owner_grants_and_approved_version", "template_dry_run_at_fires_once_immediately_with_canonical_timestamp", "template_dry_run_creates_no_rows_and_uses_no_quota", "template_dry_run_path_and_repo_canonicalization_and_bounds_match_instances"] only = true file = "crates/basal-module/src/dryrun.rs" old = "UPDATE runs SET self_input=?2,params_input=?3,grant_guards=?4 WHERE run_id=?1" @@ -2309,7 +2309,7 @@ runner = "cargo" package = "basal-module" platforms = ["linux"] target = "--test templates" -expect_red = ["template_dry_run_creates_no_rows_and_uses_no_quota"] +expect_red = ["template_dry_run_creates_no_rows_and_uses_no_quota", "instance_dry_run_uses_bound_values_owner_grants_and_approved_version", "template_dry_run_captures_self_end_with_values_and_bound_instance"] only = true file = "crates/basal-module/src/ops.rs" old = "let guards = basal_core::templates::grant_guards(&manifest, &values);" @@ -2338,7 +2338,7 @@ runner = "cargo" package = "basal-module" platforms = ["linux"] target = "--test templates" -expect_red = ["instance_dry_run_uses_bound_values_owner_grants_and_approved_version"] +expect_red = ["instance_dry_run_uses_bound_values_owner_grants_and_approved_version", "template_dry_run_at_fires_once_immediately_with_canonical_timestamp"] only = true file = "crates/basal-module/src/ops.rs" old = "serde_json::from_str(values).map_err(invalid_params)?," diff --git a/mutations.d/proto.toml b/mutations.d/proto.toml index f3723681..bf6a4dc6 100644 --- a/mutations.d/proto.toml +++ b/mutations.d/proto.toml @@ -63,7 +63,7 @@ runner = "cargo" package = "basal-proto" platforms = ["linux"] target = "--lib" -expect_red = ["tests::codemode_wire_codes_preserve_shell_and_round_trip_tool_json"] +expect_red = ["tests::codemode_wire_codes_preserve_shell_and_round_trip_tool_json", "tests::confinement_wire_tags_and_linux_fields_are_stable"] only = true file = "crates/basal-proto/src/limits.rs" old = "pub const PROTOCOL_VERSION: u32 = 9;" diff --git a/mutations.d/worker.toml b/mutations.d/worker.toml index d55c2726..c52bccb8 100644 --- a/mutations.d/worker.toml +++ b/mutations.d/worker.toml @@ -507,18 +507,18 @@ build_timeout_s = 3600 timeout_s = 600 edits = [ { file = "crates/basal-worker/Cargo.toml", old = "rquickjs.workspace = true\n", new = "rquickjs.workspace = true\nsubc-protocol = \"0.24.1\" # NON-VACUITY BREAK\n" }, - { file = "Cargo.lock", old = " \"rusqlite\",\n \"serde\",\n \"serde_json\",\n \"sha2\",\n \"subc-protocol\",\n \"tracing\",\n", new = " \"rusqlite\",\n \"serde\",\n \"serde_json\",\n \"sha2\",\n \"subc-protocol 0.30.2\",\n \"tracing\",\n" }, - { file = "Cargo.lock", old = " \"subc-client-rs\",\n \"subc-protocol\",\n \"subc-transport\",\n \"tokio\",\n \"tracing\",\n \"webpki-roots 1.0.9\",\n", new = " \"subc-client-rs\",\n \"subc-protocol 0.30.2\",\n \"subc-transport\",\n \"tokio\",\n \"tracing\",\n \"webpki-roots 1.0.9\",\n" }, - { file = "Cargo.lock", old = " \"serde\",\n \"serde_json\",\n \"sha2\",\n \"subc-client-rs\",\n \"subc-os\",\n \"subc-protocol\",\n \"subc-transport\",\n \"tokio\",\n \"tracing\",\n", new = " \"serde\",\n \"serde_json\",\n \"sha2\",\n \"subc-client-rs\",\n \"subc-os\",\n \"subc-protocol 0.30.2\",\n \"subc-transport\",\n \"tokio\",\n \"tracing\",\n" }, - { file = "Cargo.lock", old = " \"rcgen\",\n \"rusqlite\",\n \"rustls\",\n \"serde_json\",\n \"subc-protocol\",\n", new = " \"rcgen\",\n \"rusqlite\",\n \"rustls\",\n \"serde_json\",\n \"subc-protocol 0.30.2\",\n" }, - { file = "Cargo.lock", old = " \"rusqlite\",\n \"serde_json\",\n \"sha2\",\n \"subc-client-rs\",\n \"subc-protocol\",\n \"tokio\",\n \"windows-sys 0.61.2\",\n]\n", new = " \"rusqlite\",\n \"serde_json\",\n \"sha2\",\n \"subc-client-rs\",\n \"subc-protocol 0.30.2\",\n \"tokio\",\n \"windows-sys 0.61.2\",\n]\n" }, - { file = "Cargo.lock", old = " \"rquickjs\",\n \"seccompiler\",\n \"serde_json\",\n \"windows-sys 0.61.2\",\n]\n\n[[package]]\n", new = " \"rquickjs\",\n \"seccompiler\",\n \"serde_json\",\n \"subc-protocol 0.24.1\",\n \"windows-sys 0.61.2\",\n]\n\n[[package]]\n" }, - { file = "Cargo.lock", old = " \"serde_json\",\n \"subc-control\",\n \"subc-os\",\n \"subc-protocol\",\n \"subc-transport\",\n \"tokio\",\n \"tokio-util\",\n", new = " \"serde_json\",\n \"subc-control\",\n \"subc-os\",\n \"subc-protocol 0.30.2\",\n \"subc-transport\",\n \"tokio\",\n \"tokio-util\",\n" }, - { file = "Cargo.lock", old = "dependencies = [\n \"serde\",\n \"serde_json\",\n \"subc-protocol\",\n]\n", new = "dependencies = [\n \"serde\",\n \"serde_json\",\n \"subc-protocol 0.30.2\",\n]\n" }, - { file = "Cargo.lock", old = "dependencies = [\n \"libc\",\n \"rustix\",\n \"windows-sys 0.61.2\",\n]\n\n[[package]]\n", new = "dependencies = [\n \"libc\",\n \"rustix\",\n \"windows-sys 0.61.2\",\n]\n\n[[package]]\nname = \"subc-protocol\"\nversion = \"0.24.1\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"3b0fb1bc9305afe14d1202970b7e361253dba6108525b356a7e10274436bc80d\"\ndependencies = [\n \"serde\",\n \"serde_json\",\n]\n\n[[package]]\n" }, - { file = "Cargo.lock", old = " \"serde\",\n \"serde_json\",\n \"sha2\",\n \"subc-os\",\n \"subc-protocol\",\n \"subtle\",\n \"tokio\",\n]\n", new = " \"serde\",\n \"serde_json\",\n \"sha2\",\n \"subc-os\",\n \"subc-protocol 0.30.2\",\n \"subtle\",\n \"tokio\",\n]\n" }, - { file = "Cargo.lock", old = " \"serde_jcs\",\n \"serde_json\",\n \"sha2\",\n \"subc-protocol\",\n", new = " \"serde_jcs\",\n \"serde_json\",\n \"sha2\",\n \"subc-protocol 0.30.2\",\n" }, - { file = "Cargo.lock", old = " \"cortexkit-role-tool-provider\",\n \"futures-util\",\n \"serde_json\",\n \"subc-protocol\",\n", new = " \"cortexkit-role-tool-provider\",\n \"futures-util\",\n \"serde_json\",\n \"subc-protocol 0.30.2\",\n" }, + { file = "Cargo.lock", old = " \"sha2\",\n \"subc-protocol\",\n \"tracing\",\n", new = " \"sha2\",\n \"subc-protocol 0.31.0\",\n \"tracing\",\n" }, + { file = "Cargo.lock", old = " \"subc-client-rs\",\n \"subc-protocol\",\n \"subc-transport\",\n", new = " \"subc-client-rs\",\n \"subc-protocol 0.31.0\",\n \"subc-transport\",\n" }, + { file = "Cargo.lock", old = " \"subc-client-rs\",\n \"subc-os\",\n \"subc-protocol\",\n \"subc-transport\",\n", new = " \"subc-client-rs\",\n \"subc-os\",\n \"subc-protocol 0.31.0\",\n \"subc-transport\",\n" }, + { file = "Cargo.lock", old = " \"subc-client-rs\",\n \"subc-protocol\",\n \"tokio\",\n", new = " \"subc-client-rs\",\n \"subc-protocol 0.31.0\",\n \"tokio\",\n" }, + { file = "Cargo.lock", old = " \"serde_json\",\n \"subc-protocol\",\n \"windows-sys 0.61.2\",\n", new = " \"serde_json\",\n \"subc-protocol 0.31.0\",\n \"windows-sys 0.61.2\",\n" }, + { file = "Cargo.lock", old = " \"serde_json\",\n \"windows-sys 0.61.2\",\n", new = " \"serde_json\",\n \"subc-protocol 0.24.1\",\n \"windows-sys 0.61.2\",\n" }, + { file = "Cargo.lock", old = " \"sha2\",\n \"subc-protocol\",\n]\n", new = " \"sha2\",\n \"subc-protocol 0.31.0\",\n]\n" }, + { file = "Cargo.lock", old = " \"futures-util\",\n \"serde_json\",\n \"subc-protocol\",\n]\n", new = " \"futures-util\",\n \"serde_json\",\n \"subc-protocol 0.31.0\",\n]\n" }, + { file = "Cargo.lock", old = " \"subc-control\",\n \"subc-os\",\n \"subc-protocol\",\n \"subc-transport\",\n", new = " \"subc-control\",\n \"subc-os\",\n \"subc-protocol 0.31.0\",\n \"subc-transport\",\n" }, + { file = "Cargo.lock", old = " \"serde\",\n \"serde_json\",\n \"subc-protocol\",\n]\n", new = " \"serde\",\n \"serde_json\",\n \"subc-protocol 0.31.0\",\n]\n" }, + { file = "Cargo.lock", old = " \"rustix\",\n \"windows-sys 0.61.2\",\n]\n", new = " \"rustix\",\n \"windows-sys 0.61.2\",\n]\n\n[[package]]\nname = \"subc-protocol\"\nversion = \"0.24.1\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"3b0fb1bc9305afe14d1202970b7e361253dba6108525b356a7e10274436bc80d\"\ndependencies = [\n \"serde\",\n \"serde_json\",\n]\n" }, + { file = "Cargo.lock", old = " \"subc-os\",\n \"subc-protocol\",\n \"subtle\",\n", new = " \"subc-os\",\n \"subc-protocol 0.31.0\",\n \"subtle\",\n" }, ] [[control]]