diff --git a/crates/mind-body/src/cli.rs b/crates/mind-body/src/cli.rs
index 4827bf7..bb2f4b2 100644
--- a/crates/mind-body/src/cli.rs
+++ b/crates/mind-body/src/cli.rs
@@ -18,7 +18,7 @@ use chrono::{DateTime, Utc};
use eureka_pipeline::Slug;
use rust_decimal::Decimal;
-use crate::control::{BurnRate, ControlWriter, FileSource, control_path, load_state, read_effective};
+use crate::control::{BurnRate, ControlWriter, FileSource, control_path, derive, load_state};
const USAGE: &str =
"usage: mind-control [--root
] --instance show | brake hold | brake release | dial set --heat H --base-cooldown-s S --base-run-usd U";
@@ -120,6 +120,6 @@ fn show(root: &Path, instance: &Slug, out: &mut impl Write) -> Result<()> {
}
Err(error) => writeln!(out, "store: undecodable ({error:#})")?,
}
- writeln!(out, "effective: {:?}", read_effective(root, instance))?;
+ writeln!(out, "effective: {:?}", derive(&source, instance))?;
Ok(())
}
diff --git a/crates/mind-body/src/control.rs b/crates/mind-body/src/control.rs
index 19727ef..bf4a65e 100644
--- a/crates/mind-body/src/control.rs
+++ b/crates/mind-body/src/control.rs
@@ -3,9 +3,11 @@
//! `Released` carries a `Grant`, the only value that hands a run cap to the
//! launch: it cannot be built outside this module, so a cap exists only as the
//! reading of a released brake and an in-bounds dial. The Grant names the
-//! instance whose store was read, and that store's path is derived from the
-//! instance here, by the one reader: no caller supplies a path or a source, so
-//! a Grant is the proof that this instance's own root-owned store released.
+//! instance whose store was read. The store is at a fixed place, `CONTROL_ROOT`,
+//! and the one reader takes the instance only: no function, argument, variable
+//! or flag lets a caller choose a root, a path or a source, so a Grant is the
+//! proof that this instance's own root-owned store released. Only a
+//! `#[cfg(test)]` override inside this crate moves the root.
//!
//! State is a CultCache single-file store at
//! `/etc/gamecult/minds//control.cc`, root-owned and world-readable.
@@ -35,8 +37,8 @@ use eureka_pipeline::Slug;
use rust_decimal::Decimal;
use rust_decimal::prelude::ToPrimitive;
-/// Where every instance's control directory lives. Tests and the library never
-/// touch it: the root is a parameter.
+/// Where every instance's control directory lives. The reader reads only here;
+/// the operator's CLI takes its own `--root` for writing and display.
pub const CONTROL_ROOT: &str = "/etc/gamecult/minds";
/// The one key each control document has in the store.
@@ -170,7 +172,7 @@ pub struct ControlState {
impl ControlState {
/// The one derivation. Order: brake first, then dial; each failing rung is
/// its own reason.
- fn effective(&self, instance: &Slug) -> Effective {
+ pub(crate) fn effective(&self, instance: &Slug) -> Effective {
let held = |reason| Effective::Held { reason };
let Some(brake) = &self.brake else {
return held(HeldReason::BrakeAbsent);
@@ -233,45 +235,85 @@ pub fn load_state(source: &impl ControlSource) -> Result {
}
/// The only reader every organ uses (the waker now; the permit issuer and the
-/// Persona organ later). The store is `instance`'s own, at the path
-/// `control_path` derives under `root`; the caller supplies neither a path nor
-/// a source. An instance that is not a slug reads as held.
-pub fn read_effective(root: &Path, instance: &Slug) -> Effective {
- match control_path(root, instance) {
+/// Persona organ later). The store is `instance`'s own at
+/// `CONTROL_ROOT//control.cc`; the caller supplies neither a root, a
+/// path nor a source. An instance that is not a slug reads as held.
+///
+/// Nothing outside this crate can name another place:
+///
+/// ```compile_fail
+/// use eureka_pipeline::Slug;
+/// // a root is not an argument
+/// let _ = mind_body::control::read_effective(std::path::Path::new("/tmp"), &Slug("eureka".into()));
+/// ```
+///
+/// ```compile_fail
+/// // there is no reader over a source of the caller's
+/// let _ = mind_body::control::read_effective_from;
+/// ```
+///
+/// ```compile_fail
+/// use mind_body::control::Grant;
+/// // a Grant cannot be written out
+/// let _ = Grant { instance: eureka_pipeline::Slug("eureka".into()), cadence: std::time::Duration::ZERO, run_cap_usd: rust_decimal::Decimal::ONE };
+/// ```
+///
+/// ```compile_fail
+/// // and the test constructor is not in the library build
+/// let _ = mind_body::control::Grant::for_test;
+/// ```
+///
+/// The same preamble with the real call compiles:
+///
+/// ```
+/// use eureka_pipeline::Slug;
+/// let _ = mind_body::control::read_effective(&Slug("eureka".into()));
+/// ```
+pub fn read_effective(instance: &Slug) -> Effective {
+ match control_path(&control_root(), instance) {
Ok(path) => derive(&FileSource::new(path), instance),
Err(_) => Effective::Held { reason: HeldReason::Undecodable },
}
}
-fn derive(source: &impl ControlSource, instance: &Slug) -> Effective {
+#[cfg(not(test))]
+fn control_root() -> PathBuf {
+ PathBuf::from(CONTROL_ROOT)
+}
+
+/// The test seam: this crate's own tests move the root for their thread. It
+/// does not exist in a library build, and it is not a cargo feature.
+#[cfg(test)]
+thread_local! {
+ static TEST_ROOT: std::cell::RefCell> = const { std::cell::RefCell::new(None) };
+}
+
+#[cfg(test)]
+fn control_root() -> PathBuf {
+ TEST_ROOT.with(|root| root.borrow().clone()).unwrap_or_else(|| PathBuf::from(CONTROL_ROOT))
+}
+
+/// Runs `body` with the reader pointed at `root` on this thread.
+#[cfg(test)]
+pub(crate) fn with_root(root: &Path, body: impl FnOnce() -> T) -> T {
+ let before = TEST_ROOT.with(|cell| cell.replace(Some(root.to_path_buf())));
+ let result = body();
+ TEST_ROOT.with(|cell| cell.replace(before));
+ result
+}
+
+/// The derivation over any source. The reader and the CLI's `show` (display
+/// only: its output is text) are its callers; nothing public returns its result
+/// for a source of the caller's.
+pub(crate) fn derive(source: &impl ControlSource, instance: &Slug) -> Effective {
match load_state(source) {
Ok(state) => state.effective(instance),
Err(_) => Effective::Held { reason: HeldReason::Undecodable },
}
}
-/// The same derivation over a fake store, for tests of the reader; the Grant it
-/// makes names the instance given, and the launch judges that like any other.
#[cfg(test)]
-pub(crate) fn read_effective_from(source: &impl ControlSource, instance: &Slug) -> Effective {
- derive(source, instance)
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn a_source_that_fails_reads_as_held() {
- struct Failing;
- impl ControlSource for Failing {
- fn snapshot(&self) -> Result> {
- Err(anyhow::anyhow!("disk gone"))
- }
- }
- assert_eq!(read_effective_from(&Failing, &Slug("eureka".into())), Effective::Held { reason: HeldReason::Undecodable });
- }
-}
+mod tests;
/// The operator's writer over one control file. Each setter replaces its
/// document whole; the other document is untouched. The file is created on the
diff --git a/crates/mind-body/src/control/tests.rs b/crates/mind-body/src/control/tests.rs
new file mode 100644
index 0000000..d4bb8fd
--- /dev/null
+++ b/crates/mind-body/src/control/tests.rs
@@ -0,0 +1,414 @@
+//! The reader's tests, in the crate because they move the reader's root with
+//! the `#[cfg(test)]` seam: no caller outside the crate can. Every test works in
+//! a temporary directory through the same file door the units use; nothing
+//! touches `/etc`. They run as root in the verify container like the writer's.
+
+use std::path::{Path, PathBuf};
+use std::time::Duration;
+
+use chrono::{DateTime, TimeZone, Utc};
+use cultcache_rs::{CultCache, DatabaseEntry, SingleFileMessagePackBackingStore};
+use eureka_pipeline::Slug;
+use rust_decimal::Decimal;
+use std::str::FromStr;
+
+use super::*;
+
+fn dec(text: &str) -> Decimal {
+ Decimal::from_str(text).unwrap()
+}
+
+fn at(seconds: i64) -> DateTime {
+ Utc.timestamp_opt(1_800_000_000 + seconds, 0).unwrap()
+}
+
+fn dial(heat: &str, cooldown: u32, run_usd: &str) -> BurnRate {
+ BurnRate { heat: dec(heat), base_cooldown_s: cooldown, base_run_usd: dec(run_usd), set_at: at(0), set_by: "op".into() }
+}
+
+/// The store of the instance `eureka` under the root `dir`.
+fn store_path(dir: &Path) -> PathBuf {
+ dir.join("eureka").join("control.cc")
+}
+
+fn held(reason: HeldReason) -> Effective {
+ Effective::Held { reason }
+}
+
+/// A written store: brake released and the given dial, through the real writer.
+fn released_store(dir: &Path, dial: BurnRate) -> PathBuf {
+ let path = store_path(dir);
+ let mut writer = ControlWriter::open(&path).unwrap();
+ writer.set_brake(true, at(0), "op").unwrap();
+ writer.set_dial(dial).unwrap();
+ path
+}
+
+/// The real reader's answer for the store at `//control.cc`,
+/// with the reader's root moved to `` on this thread.
+fn effective(path: &Path) -> Effective {
+ let directory = path.parent().unwrap();
+ let instance = Slug(directory.file_name().unwrap().to_str().unwrap().into());
+ with_root(directory.parent().unwrap(), || read_effective(&instance))
+}
+
+/// A dial written around the writer's bounds check, so the reader's own check
+/// is what is under test.
+fn write_unchecked_dial(path: &Path, dial: &BurnRate) {
+ let mut cache = CultCache::new();
+ cache.register_entry_type::().unwrap();
+ cache.register_entry_type::().unwrap();
+ cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(path)).unwrap();
+ cache.pull_all_backing_stores().unwrap();
+ cache.put(DIAL_KEY, dial).unwrap();
+}
+
+#[test]
+fn a_source_that_fails_reads_as_held() {
+ struct Failing;
+ impl ControlSource for Failing {
+ fn snapshot(&self) -> Result> {
+ Err(anyhow::anyhow!("disk gone"))
+ }
+ }
+ assert_eq!(derive(&Failing, &Slug("eureka".into())), Effective::Held { reason: HeldReason::Undecodable });
+}
+
+#[test]
+fn an_absent_store_reads_as_held() {
+ let dir = tempfile::tempdir().unwrap();
+ assert_eq!(effective(&store_path(dir.path())), held(HeldReason::BrakeAbsent));
+ assert!(!store_path(dir.path()).exists(), "reading must not create the store");
+}
+
+#[test]
+fn an_absent_brake_reads_as_held_even_with_a_dial() {
+ let dir = tempfile::tempdir().unwrap();
+ let path = store_path(dir.path());
+ ControlWriter::open(&path).unwrap().set_dial(dial("1", 3600, "1")).unwrap();
+ assert_eq!(effective(&path), held(HeldReason::BrakeAbsent));
+}
+
+#[test]
+fn an_undecodable_store_reads_as_held() {
+ let dir = tempfile::tempdir().unwrap();
+ let path = released_store(dir.path(), dial("1", 3600, "1"));
+ let good = std::fs::read(&path).unwrap();
+
+ // Garbage in place of the store.
+ std::fs::write(&path, b"this is not a cultcache store").unwrap();
+ assert_eq!(effective(&path), held(HeldReason::Undecodable));
+
+ // A store cut off mid-document.
+ std::fs::write(&path, &good[..good.len() / 2]).unwrap();
+ assert_eq!(effective(&path), held(HeldReason::Undecodable));
+
+ // The untouched store is still released, so the two reads above were the damage.
+ std::fs::write(&path, &good).unwrap();
+ assert!(matches!(effective(&path), Effective::Released(_)));
+}
+
+#[test]
+fn a_path_that_cannot_be_read_as_a_file_reads_as_held() {
+ let dir = tempfile::tempdir().unwrap();
+ // A directory sits where the store should be: it exists and cannot be read as a file.
+ let path = store_path(dir.path());
+ std::fs::create_dir_all(&path).unwrap();
+ assert_eq!(effective(&path), held(HeldReason::Undecodable));
+}
+
+#[test]
+fn an_unknown_document_type_makes_the_store_undecodable() {
+ #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)]
+ #[cultcache(type = "eureka.control.something_else.v1", schema = "Other")]
+ struct Other {
+ #[cultcache(key = 0)]
+ value: u32,
+ }
+ let dir = tempfile::tempdir().unwrap();
+ let path = released_store(dir.path(), dial("1", 3600, "1"));
+ let mut cache = CultCache::new();
+ cache.register_entry_type::().unwrap();
+ cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&path)).unwrap();
+ cache.put("x", &Other { value: 1 }).unwrap();
+ // The store now holds a released brake, a good dial and a foreign document.
+ assert_eq!(effective(&path), held(HeldReason::Undecodable));
+}
+
+#[test]
+fn a_brake_payload_that_does_not_decode_makes_the_store_undecodable() {
+ // Same type id as the brake, a different shape: the payload cannot decode as a Brake.
+ #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)]
+ #[cultcache(type = "eureka.control.brake.v1", schema = "ControlBrake")]
+ struct WrongBrake {
+ #[cultcache(key = 0)]
+ released: String,
+ }
+ let dir = tempfile::tempdir().unwrap();
+ let path = store_path(dir.path());
+ let mut cache = CultCache::new();
+ cache.register_entry_type::().unwrap();
+ cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&path)).unwrap();
+ cache.put(BRAKE_KEY, &WrongBrake { released: "yes".into() }).unwrap();
+ assert_eq!(effective(&path), held(HeldReason::Undecodable));
+}
+
+#[test]
+fn a_decode_failure_outranks_a_held_brake() {
+ let dir = tempfile::tempdir().unwrap();
+ let path = released_store(dir.path(), dial("1", 3600, "1"));
+ ControlWriter::open(&path).unwrap().set_brake(false, at(5), "op").unwrap();
+ assert_eq!(effective(&path), held(HeldReason::BrakeHeld));
+ std::fs::write(&path, b"junk").unwrap();
+ assert_eq!(effective(&path), held(HeldReason::Undecodable));
+}
+
+#[test]
+fn a_released_brake_with_no_dial_reads_held_dial_absent() {
+ let dir = tempfile::tempdir().unwrap();
+ let path = store_path(dir.path());
+ ControlWriter::open(&path).unwrap().set_brake(true, at(0), "op").unwrap();
+ assert_eq!(effective(&path), held(HeldReason::DialAbsent));
+}
+
+#[test]
+fn dial_bounds_are_inclusive_at_both_ends() {
+ for (heat, expected_in) in [("0.05", true), ("2.0", true), ("0.0499", false), ("2.0001", false), ("0", false), ("-1", false), ("3", false)] {
+ let dir = tempfile::tempdir().unwrap();
+ let path = released_store_unchecked(dir.path(), dial(heat, 3600, "1"));
+ let got = effective(&path);
+ if expected_in {
+ assert!(matches!(got, Effective::Released(_)), "heat {heat}: {got:?}");
+ } else {
+ assert_eq!(got, held(HeldReason::DialOutOfBounds), "heat {heat}");
+ }
+ }
+}
+
+#[test]
+fn a_zero_base_cooldown_or_a_non_positive_run_cost_is_out_of_bounds() {
+ for bad in [dial("1", 0, "1"), dial("1", 3600, "0"), dial("1", 3600, "-0.5")] {
+ let dir = tempfile::tempdir().unwrap();
+ let path = released_store_unchecked(dir.path(), bad.clone());
+ assert_eq!(effective(&path), held(HeldReason::DialOutOfBounds), "{bad:?}");
+ }
+ let dir = tempfile::tempdir().unwrap();
+ let smallest = released_store_unchecked(dir.path(), dial("1", 1, "0.000001"));
+ assert!(matches!(effective(&smallest), Effective::Released(_)));
+}
+
+fn released_store_unchecked(dir: &Path, bad: BurnRate) -> PathBuf {
+ let path = store_path(dir);
+ ControlWriter::open(&path).unwrap().set_brake(true, at(0), "op").unwrap();
+ write_unchecked_dial(&path, &bad);
+ path
+}
+
+#[test]
+fn cadence_and_run_cap_are_the_dial_divided_and_multiplied_by_heat() {
+ for (heat, cooldown, run_usd, cadence, cap) in [
+ ("0.5", 3600u32, "5", Duration::from_secs(7200), dec("2.5")),
+ ("2.0", 3600, "5", Duration::from_secs(1800), dec("10.0")),
+ ("1", 600, "3", Duration::from_secs(600), dec("3")),
+ ("0.05", 90, "4", Duration::from_secs(1800), dec("0.20")),
+ ("1.5", 10, "2", Duration::new(6, 666_666_667), dec("3.0")),
+ ("2.0", 1, "0.25", Duration::from_millis(500), dec("0.500")),
+ ] {
+ let dir = tempfile::tempdir().unwrap();
+ let path = released_store(dir.path(), dial(heat, cooldown, run_usd));
+ let Effective::Released(grant) = effective(&path) else { panic!("heat {heat} cooldown {cooldown} run {run_usd}: not released") };
+ assert_eq!(grant.cadence(), cadence, "heat {heat} cooldown {cooldown} run {run_usd}");
+ assert_eq!(grant.run_cap_usd(), cap, "heat {heat} cooldown {cooldown} run {run_usd}");
+ }
+}
+
+#[test]
+fn the_operators_last_write_is_what_is_in_force_and_provenance_round_trips() {
+ let dir = tempfile::tempdir().unwrap();
+ let path = released_store(dir.path(), dial("1", 3600, "1"));
+ assert!(matches!(effective(&path), Effective::Released(_)));
+
+ ControlWriter::open(&path).unwrap().set_brake(false, at(60), "alice").unwrap();
+ assert_eq!(effective(&path), held(HeldReason::BrakeHeld));
+ let state = load_state(&FileSource::new(&path)).unwrap();
+ let brake = state.brake.unwrap();
+ assert_eq!((brake.released, brake.set_at, brake.set_by.as_str()), (false, at(60), "alice"));
+ // The dial survives the brake write untouched.
+ assert_eq!(state.dial.unwrap().set_by, "op");
+
+ ControlWriter::open(&path).unwrap().set_brake(true, at(120), "bob").unwrap();
+ assert!(matches!(effective(&path), Effective::Released(_)));
+ let brake = load_state(&FileSource::new(&path)).unwrap().brake.unwrap();
+ assert_eq!((brake.released, brake.set_at, brake.set_by.as_str()), (true, at(120), "bob"));
+}
+
+#[test]
+fn reading_writes_nothing_and_takes_no_lock_file() {
+ let dir = tempfile::tempdir().unwrap();
+ let path = released_store(dir.path(), dial("1", 3600, "1"));
+ let store_dir = path.parent().unwrap();
+ let listing = |dir: &Path| {
+ let mut names: Vec<_> = std::fs::read_dir(dir).unwrap().map(|e| e.unwrap().file_name()).collect();
+ names.sort();
+ names
+ };
+ // The writer left its sibling lock file; remove it, so a reader that wants one has to create it.
+ for entry in std::fs::read_dir(store_dir).unwrap() {
+ let entry = entry.unwrap().path();
+ if entry != path {
+ std::fs::remove_file(entry).unwrap();
+ }
+ }
+ let before = (listing(store_dir), std::fs::read(&path).unwrap());
+ assert!(matches!(effective(&path), Effective::Released(_)));
+ assert_eq!((listing(store_dir), std::fs::read(&path).unwrap()), before);
+}
+
+
+/// A dial document under the dial's type id whose payload is not a dial.
+#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)]
+#[cultcache(type = "eureka.control.burn_rate.v1", schema = "ControlBurnRate")]
+struct WrongDial {
+ #[cultcache(key = 0)]
+ heat: String,
+}
+
+fn write_wrong_dial(path: &Path, heat: &str) {
+ let mut cache = CultCache::new();
+ cache.register_entry_type::().unwrap();
+ cache.register_entry_type::().unwrap();
+ cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(path)).unwrap();
+ cache.pull_all_backing_stores().unwrap();
+ cache.put(mind_body::control::DIAL_KEY, &WrongDial { heat: heat.into() }).unwrap();
+}
+
+#[test]
+fn a_dial_that_does_not_decode_reads_held_whatever_the_brake_says() {
+ for brake_released in [true, false] {
+ for heat in ["not a number", "NaN", ""] {
+ let dir = tempfile::tempdir().unwrap();
+ let path = store_path(dir.path());
+ ControlWriter::open(&path).unwrap().set_brake(brake_released, at(0), "op").unwrap();
+ write_wrong_dial(&path, heat);
+ assert_eq!(
+ effective(&path),
+ held(HeldReason::Undecodable),
+ "brake released={brake_released}, dial heat {heat:?}: a dial that cannot be read is never replaced by a default"
+ );
+ }
+ }
+}
+
+
+mod grant {
+ //! A Grant is the proof that this instance's own control store released: the
+ //! reader derives the path from the instance, and a launch refuses a Grant
+ //! read for another instance before it asks the mind anything.
+
+ use anyhow::{Result, anyhow};
+ use cultnet_rs::Selection;
+ use eureka_pipeline::{PipelineDocument, RunTurn};
+ use huginn_mind::{PipelineAdmissionOutcome, PipelineSelectionPage};
+
+ use super::*;
+ use crate::launch::{Clock, Declined, LaunchOutcome, LaunchRequest, Launcher, Ports, open_and_launch};
+ use crate::queue::MindPort;
+
+ fn slug(name: &str) -> Slug {
+ Slug(name.into())
+ }
+
+ fn release(root: &Path, instance: &str) {
+ let mut writer = ControlWriter::open(control_path(root, &slug(instance)).unwrap()).unwrap();
+ writer.set_brake(true, at(0), "op").unwrap();
+ writer.set_dial(dial("1", 3600, "5")).unwrap();
+ }
+
+ fn read(root: &Path, instance: &str) -> Effective {
+ with_root(root, || read_effective(&slug(instance)))
+ }
+
+ /// A mind that answers nothing: a launch that reaches it has gone past the
+ /// instance check.
+ struct SilentMind(Slug);
+
+ impl MindPort for SilentMind {
+ fn instance(&self) -> &Slug {
+ &self.0
+ }
+
+ fn query(&self, _selection: &Selection) -> Result {
+ Err(anyhow!("the launch asked the mind"))
+ }
+
+ fn admit(&self, _agent: &str, _session: &str, _documents: Vec) -> Result {
+ Err(anyhow!("the launch admitted"))
+ }
+ }
+
+ struct NoUnits;
+
+ impl Launcher for NoUnits {
+ fn start(&self, _instance: &Slug, _turn: RunTurn) -> Result<()> {
+ Err(anyhow!("the launch started a unit"))
+ }
+
+ fn alive(&self, _instance: &Slug, _turn: RunTurn) -> bool {
+ false
+ }
+ }
+
+ struct Now;
+
+ impl Clock for Now {
+ fn now(&self) -> DateTime {
+ at(100)
+ }
+ }
+
+ fn launch_as(mind_instance: &str, grant: Grant, turn: RunTurn) -> Result {
+ let mind = SilentMind(slug(mind_instance));
+ let ports = Ports { mind: &mind, launcher: &NoUnits, clock: &Now, host: "host" };
+ open_and_launch(&ports, LaunchRequest { turn, claims: vec![], agent: "agent".into(), grant })
+ }
+
+ #[test]
+ fn the_reader_makes_a_grant_for_the_instance_whose_store_it_read() {
+ let root = tempfile::tempdir().unwrap();
+ release(root.path(), "void");
+ let Effective::Released(grant) = read(root.path(), "void") else { panic!("void's store is released") };
+ assert_eq!(grant.instance(), &slug("void"));
+ assert_eq!(grant.run_cap_usd(), dec("5"));
+ }
+
+ #[test]
+ fn another_instances_released_store_yields_no_grant_for_this_one() {
+ let root = tempfile::tempdir().unwrap();
+ release(root.path(), "void");
+ assert_eq!(read(root.path(), "eureka"), held(HeldReason::BrakeAbsent));
+ for walk in ["../void", "void/..", "eureka/../void", "/void"] {
+ assert_eq!(read(root.path(), walk), held(HeldReason::Undecodable), "{walk}");
+ }
+ }
+
+ #[test]
+ fn a_grant_read_for_one_instance_cannot_launch_another() {
+ let root = tempfile::tempdir().unwrap();
+ release(root.path(), "void");
+ for turn in [RunTurn::SelfRun, RunTurn::PersonaTurn] {
+ let Effective::Released(grant) = read(root.path(), "void") else { panic!("void's store is released") };
+ // The mind is eureka's; the silent mind and the unit-less launcher fail loudly if the launch goes on.
+ let outcome = launch_as("eureka", grant, turn).unwrap();
+ assert_eq!(outcome, LaunchOutcome::Refused(Declined::GrantForOtherInstance), "{turn:?}");
+ }
+ }
+
+ #[test]
+ fn the_matching_grant_is_not_stopped_by_the_instance_check() {
+ let root = tempfile::tempdir().unwrap();
+ release(root.path(), "void");
+ let Effective::Released(grant) = read(root.path(), "void") else { panic!("void's store is released") };
+ let error = launch_as("void", grant, RunTurn::SelfRun).unwrap_err();
+ assert!(format!("{error:#}").contains("asked the mind"), "{error:#}");
+ }
+}
diff --git a/crates/mind-body/src/launch.rs b/crates/mind-body/src/launch.rs
index c3ed530..4cb3190 100644
--- a/crates/mind-body/src/launch.rs
+++ b/crates/mind-body/src/launch.rs
@@ -850,19 +850,25 @@ mod tests {
fn a_grant_read_for_another_instance_opens_nothing_and_starts_nothing() {
let rig = Rig::new();
rig.mind.committed(vec![spec("x")]);
- for turn in [RunTurn::SelfRun, RunTurn::PersonaTurn] {
- let claims = if turn == RunTurn::SelfRun { vec![spec_ref("x")] } else { vec![] };
- let ports = Ports { mind: &rig.mind, launcher: &rig.launcher, clock: &rig.clock, host: "yggdrasil-host" };
- let grant = Grant::for_test(Slug("another-instance".into()), StdDuration::from_secs(60), five());
- let outcome = open_and_launch(&ports, LaunchRequest { turn, claims, agent: "agent-x".into(), grant }).unwrap();
- assert_eq!(outcome, LaunchOutcome::Refused(Declined::GrantForOtherInstance), "{turn:?}");
+ // Forgeries shaped like the real name: the same length and prefix, differing only at the end;
+ // a prefix of it; and a name it is a prefix of. Each is checked whole.
+ let forged = [format!("{}k", &INSTANCE[..INSTANCE.len() - 1]), INSTANCE[..INSTANCE.len() - 1].to_string(), format!("{INSTANCE}-test"), "another-instance".to_string()];
+ assert_eq!(forged[0].len(), INSTANCE.len());
+ for name in forged {
+ for turn in [RunTurn::SelfRun, RunTurn::PersonaTurn] {
+ let claims = if turn == RunTurn::SelfRun { vec![spec_ref("x")] } else { vec![] };
+ let ports = Ports { mind: &rig.mind, launcher: &rig.launcher, clock: &rig.clock, host: "yggdrasil-host" };
+ let grant = Grant::for_test(Slug(name.clone()), StdDuration::from_secs(60), five());
+ let outcome = open_and_launch(&ports, LaunchRequest { turn, claims, agent: "agent-x".into(), grant }).unwrap();
+ assert_eq!(outcome, LaunchOutcome::Refused(Declined::GrantForOtherInstance), "{name} {turn:?}");
+ }
}
assert_eq!((rig.runs(), rig.started()), (0, 0));
assert!(matches!(rig.launch(RunTurn::SelfRun, &[spec_ref("x")], five()), LaunchOutcome::Launched { .. }), "the mind's own Grant launches");
}
#[test]
- fn a_persona_turn_with_claims_is_refused_and_opens_nothing() {
+ fn a_persona_turn_with_a_claim_of_any_kind_is_refused_and_opens_nothing() {
let rig = Rig::new();
rig.mind.committed(vec![spec("x"), spec("blocked")]);
rig.mind.committed(vec![question_in("fork", &spec_ref("blocked"))]);
@@ -871,6 +877,11 @@ mod tests {
let outcome = rig.launch(RunTurn::PersonaTurn, &[spec_ref(item)], five());
assert_eq!(outcome, LaunchOutcome::Refused(Declined::PersonaRunTakesNoClaims), "{item}");
}
+ // And a claim of every kind the leaf has, whether or not the document exists.
+ for kind in PipelineKind::ALL {
+ let outcome = rig.launch(RunTurn::PersonaTurn, &[reference(*kind, "no-such-document")], five());
+ assert_eq!(outcome, LaunchOutcome::Refused(Declined::PersonaRunTakesNoClaims), "{kind:?}");
+ }
assert_eq!((rig.runs(), rig.started()), (0, 0));
assert!(matches!(rig.launch(RunTurn::PersonaTurn, &[], five()), LaunchOutcome::Launched { .. }));
}
diff --git a/crates/mind-body/tests/control.rs b/crates/mind-body/tests/control.rs
index 8f7f191..84f13e0 100644
--- a/crates/mind-body/tests/control.rs
+++ b/crates/mind-body/tests/control.rs
@@ -14,9 +14,7 @@ use std::time::Duration;
use chrono::{DateTime, TimeZone, Utc};
use cultcache_rs::{CultCache, DatabaseEntry, SingleFileMessagePackBackingStore};
-use mind_body::control::{
- BRAKE_KEY, BurnRate, ControlWriter, Effective, FileSource, HeldReason, control_path, load_state, read_effective,
-};
+use mind_body::control::{BurnRate, ControlWriter, FileSource, control_path, load_state};
use eureka_pipeline::Slug;
use rust_decimal::Decimal;
use std::str::FromStr;
@@ -38,10 +36,6 @@ fn store_path(dir: &Path) -> PathBuf {
dir.join("eureka").join("control.cc")
}
-fn held(reason: HeldReason) -> Effective {
- Effective::Held { reason }
-}
-
/// A written store: brake released and the given dial, through the real writer.
fn released_store(dir: &Path, dial: BurnRate) -> PathBuf {
let path = store_path(dir);
@@ -51,193 +45,6 @@ fn released_store(dir: &Path, dial: BurnRate) -> PathBuf {
path
}
-/// The reader's answer for the store at `//control.cc`: the
-/// reader derives that path itself from the root and the instance.
-fn effective(path: &Path) -> Effective {
- let directory = path.parent().unwrap();
- let instance = Slug(directory.file_name().unwrap().to_str().unwrap().into());
- read_effective(directory.parent().unwrap(), &instance)
-}
-
-/// A dial written around the writer's bounds check, so the reader's own check
-/// is what is under test.
-fn write_unchecked_dial(path: &Path, dial: &BurnRate) {
- let mut cache = CultCache::new();
- cache.register_entry_type::().unwrap();
- cache.register_entry_type::().unwrap();
- cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(path)).unwrap();
- cache.pull_all_backing_stores().unwrap();
- cache.put(mind_body::control::DIAL_KEY, dial).unwrap();
-}
-
-#[test]
-fn an_absent_store_reads_as_held() {
- let dir = tempfile::tempdir().unwrap();
- assert_eq!(effective(&store_path(dir.path())), held(HeldReason::BrakeAbsent));
- assert!(!store_path(dir.path()).exists(), "reading must not create the store");
-}
-
-#[test]
-fn an_absent_brake_reads_as_held_even_with_a_dial() {
- let dir = tempfile::tempdir().unwrap();
- let path = store_path(dir.path());
- ControlWriter::open(&path).unwrap().set_dial(dial("1", 3600, "1")).unwrap();
- assert_eq!(effective(&path), held(HeldReason::BrakeAbsent));
-}
-
-#[test]
-fn an_undecodable_store_reads_as_held() {
- let dir = tempfile::tempdir().unwrap();
- let path = released_store(dir.path(), dial("1", 3600, "1"));
- let good = std::fs::read(&path).unwrap();
-
- // Garbage in place of the store.
- std::fs::write(&path, b"this is not a cultcache store").unwrap();
- assert_eq!(effective(&path), held(HeldReason::Undecodable));
-
- // A store cut off mid-document.
- std::fs::write(&path, &good[..good.len() / 2]).unwrap();
- assert_eq!(effective(&path), held(HeldReason::Undecodable));
-
- // The untouched store is still released, so the two reads above were the damage.
- std::fs::write(&path, &good).unwrap();
- assert!(matches!(effective(&path), Effective::Released(_)));
-}
-
-#[test]
-fn a_path_that_cannot_be_read_as_a_file_reads_as_held() {
- let dir = tempfile::tempdir().unwrap();
- // A directory sits where the store should be: it exists and cannot be read as a file.
- let path = store_path(dir.path());
- std::fs::create_dir_all(&path).unwrap();
- assert_eq!(effective(&path), held(HeldReason::Undecodable));
-}
-
-#[test]
-fn an_unknown_document_type_makes_the_store_undecodable() {
- #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)]
- #[cultcache(type = "eureka.control.something_else.v1", schema = "Other")]
- struct Other {
- #[cultcache(key = 0)]
- value: u32,
- }
- let dir = tempfile::tempdir().unwrap();
- let path = released_store(dir.path(), dial("1", 3600, "1"));
- let mut cache = CultCache::new();
- cache.register_entry_type::().unwrap();
- cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&path)).unwrap();
- cache.put("x", &Other { value: 1 }).unwrap();
- // The store now holds a released brake, a good dial and a foreign document.
- assert_eq!(effective(&path), held(HeldReason::Undecodable));
-}
-
-#[test]
-fn a_brake_payload_that_does_not_decode_makes_the_store_undecodable() {
- // Same type id as the brake, a different shape: the payload cannot decode as a Brake.
- #[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)]
- #[cultcache(type = "eureka.control.brake.v1", schema = "ControlBrake")]
- struct WrongBrake {
- #[cultcache(key = 0)]
- released: String,
- }
- let dir = tempfile::tempdir().unwrap();
- let path = store_path(dir.path());
- let mut cache = CultCache::new();
- cache.register_entry_type::().unwrap();
- cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&path)).unwrap();
- cache.put(BRAKE_KEY, &WrongBrake { released: "yes".into() }).unwrap();
- assert_eq!(effective(&path), held(HeldReason::Undecodable));
-}
-
-#[test]
-fn a_decode_failure_outranks_a_held_brake() {
- let dir = tempfile::tempdir().unwrap();
- let path = released_store(dir.path(), dial("1", 3600, "1"));
- ControlWriter::open(&path).unwrap().set_brake(false, at(5), "op").unwrap();
- assert_eq!(effective(&path), held(HeldReason::BrakeHeld));
- std::fs::write(&path, b"junk").unwrap();
- assert_eq!(effective(&path), held(HeldReason::Undecodable));
-}
-
-#[test]
-fn a_released_brake_with_no_dial_reads_held_dial_absent() {
- let dir = tempfile::tempdir().unwrap();
- let path = store_path(dir.path());
- ControlWriter::open(&path).unwrap().set_brake(true, at(0), "op").unwrap();
- assert_eq!(effective(&path), held(HeldReason::DialAbsent));
-}
-
-#[test]
-fn dial_bounds_are_inclusive_at_both_ends() {
- for (heat, expected_in) in [("0.05", true), ("2.0", true), ("0.0499", false), ("2.0001", false), ("0", false), ("-1", false), ("3", false)] {
- let dir = tempfile::tempdir().unwrap();
- let path = released_store_unchecked(dir.path(), dial(heat, 3600, "1"));
- let got = effective(&path);
- if expected_in {
- assert!(matches!(got, Effective::Released(_)), "heat {heat}: {got:?}");
- } else {
- assert_eq!(got, held(HeldReason::DialOutOfBounds), "heat {heat}");
- }
- }
-}
-
-#[test]
-fn a_zero_base_cooldown_or_a_non_positive_run_cost_is_out_of_bounds() {
- for bad in [dial("1", 0, "1"), dial("1", 3600, "0"), dial("1", 3600, "-0.5")] {
- let dir = tempfile::tempdir().unwrap();
- let path = released_store_unchecked(dir.path(), bad.clone());
- assert_eq!(effective(&path), held(HeldReason::DialOutOfBounds), "{bad:?}");
- }
- let dir = tempfile::tempdir().unwrap();
- let smallest = released_store_unchecked(dir.path(), dial("1", 1, "0.000001"));
- assert!(matches!(effective(&smallest), Effective::Released(_)));
-}
-
-fn released_store_unchecked(dir: &Path, bad: BurnRate) -> PathBuf {
- let path = store_path(dir);
- ControlWriter::open(&path).unwrap().set_brake(true, at(0), "op").unwrap();
- write_unchecked_dial(&path, &bad);
- path
-}
-
-#[test]
-fn cadence_and_run_cap_are_the_dial_divided_and_multiplied_by_heat() {
- for (heat, cooldown, run_usd, cadence, cap) in [
- ("0.5", 3600u32, "5", Duration::from_secs(7200), dec("2.5")),
- ("2.0", 3600, "5", Duration::from_secs(1800), dec("10.0")),
- ("1", 600, "3", Duration::from_secs(600), dec("3")),
- ("0.05", 90, "4", Duration::from_secs(1800), dec("0.20")),
- ("1.5", 10, "2", Duration::new(6, 666_666_667), dec("3.0")),
- ("2.0", 1, "0.25", Duration::from_millis(500), dec("0.500")),
- ] {
- let dir = tempfile::tempdir().unwrap();
- let path = released_store(dir.path(), dial(heat, cooldown, run_usd));
- let Effective::Released(grant) = effective(&path) else { panic!("heat {heat} cooldown {cooldown} run {run_usd}: not released") };
- assert_eq!(grant.cadence(), cadence, "heat {heat} cooldown {cooldown} run {run_usd}");
- assert_eq!(grant.run_cap_usd(), cap, "heat {heat} cooldown {cooldown} run {run_usd}");
- }
-}
-
-#[test]
-fn the_operators_last_write_is_what_is_in_force_and_provenance_round_trips() {
- let dir = tempfile::tempdir().unwrap();
- let path = released_store(dir.path(), dial("1", 3600, "1"));
- assert!(matches!(effective(&path), Effective::Released(_)));
-
- ControlWriter::open(&path).unwrap().set_brake(false, at(60), "alice").unwrap();
- assert_eq!(effective(&path), held(HeldReason::BrakeHeld));
- let state = load_state(&FileSource::new(&path)).unwrap();
- let brake = state.brake.unwrap();
- assert_eq!((brake.released, brake.set_at, brake.set_by.as_str()), (false, at(60), "alice"));
- // The dial survives the brake write untouched.
- assert_eq!(state.dial.unwrap().set_by, "op");
-
- ControlWriter::open(&path).unwrap().set_brake(true, at(120), "bob").unwrap();
- assert!(matches!(effective(&path), Effective::Released(_)));
- let brake = load_state(&FileSource::new(&path)).unwrap().brake.unwrap();
- assert_eq!((brake.released, brake.set_at, brake.set_by.as_str()), (true, at(120), "bob"));
-}
-
#[test]
fn setting_the_dial_replaces_it_whole_and_keeps_the_brake() {
let dir = tempfile::tempdir().unwrap();
@@ -262,28 +69,6 @@ fn the_writer_refuses_an_out_of_bounds_dial_and_leaves_the_store_unchanged() {
}
}
-#[test]
-fn reading_writes_nothing_and_takes_no_lock_file() {
- let dir = tempfile::tempdir().unwrap();
- let path = released_store(dir.path(), dial("1", 3600, "1"));
- let store_dir = path.parent().unwrap();
- let listing = |dir: &Path| {
- let mut names: Vec<_> = std::fs::read_dir(dir).unwrap().map(|e| e.unwrap().file_name()).collect();
- names.sort();
- names
- };
- // The writer left its sibling lock file; remove it, so a reader that wants one has to create it.
- for entry in std::fs::read_dir(store_dir).unwrap() {
- let entry = entry.unwrap().path();
- if entry != path {
- std::fs::remove_file(entry).unwrap();
- }
- }
- let before = (listing(store_dir), std::fs::read(&path).unwrap());
- assert!(matches!(effective(&path), Effective::Released(_)));
- assert_eq!((listing(store_dir), std::fs::read(&path).unwrap()), before);
-}
-
#[test]
fn the_control_path_is_derived_from_a_valid_instance_only() {
let root = Path::new(mind_body::control::CONTROL_ROOT);
@@ -292,41 +77,6 @@ fn the_control_path_is_derived_from_a_valid_instance_only() {
assert!(control_path(root, &Slug(bad.into())).is_err(), "{bad:?}");
}
}
-
-/// A dial document under the dial's type id whose payload is not a dial.
-#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)]
-#[cultcache(type = "eureka.control.burn_rate.v1", schema = "ControlBurnRate")]
-struct WrongDial {
- #[cultcache(key = 0)]
- heat: String,
-}
-
-fn write_wrong_dial(path: &Path, heat: &str) {
- let mut cache = CultCache::new();
- cache.register_entry_type::().unwrap();
- cache.register_entry_type::().unwrap();
- cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(path)).unwrap();
- cache.pull_all_backing_stores().unwrap();
- cache.put(mind_body::control::DIAL_KEY, &WrongDial { heat: heat.into() }).unwrap();
-}
-
-#[test]
-fn a_dial_that_does_not_decode_reads_held_whatever_the_brake_says() {
- for brake_released in [true, false] {
- for heat in ["not a number", "NaN", ""] {
- let dir = tempfile::tempdir().unwrap();
- let path = store_path(dir.path());
- ControlWriter::open(&path).unwrap().set_brake(brake_released, at(0), "op").unwrap();
- write_wrong_dial(&path, heat);
- assert_eq!(
- effective(&path),
- held(HeldReason::Undecodable),
- "brake released={brake_released}, dial heat {heat:?}: a dial that cannot be read is never replaced by a default"
- );
- }
- }
-}
-
#[cfg(unix)]
mod modes {
use super::*;
@@ -391,7 +141,7 @@ mod modes {
);
assert!(std::fs::OpenOptions::new().write(true).open(&path).is_err());
assert!(std::fs::OpenOptions::new().write(true).open(path.with_file_name("control.cc.lock")).is_err());
- assert!(matches!(effective(&path), Effective::Released(_)), "a non-root user can still read the store");
+ assert!(load_state(&FileSource::new(&path)).unwrap().brake.unwrap().released, "a non-root user can still read the store");
}
other => panic!("unknown role {other}"),
}
diff --git a/crates/mind-body/tests/forge.rs b/crates/mind-body/tests/forge.rs
new file mode 100644
index 0000000..ba7f92b
--- /dev/null
+++ b/crates/mind-body/tests/forge.rs
@@ -0,0 +1,66 @@
+//! The brake-grant rule seen from outside the crate: the only reader takes the
+//! instance, so whatever a caller builds elsewhere (a store in a temporary
+//! directory, a symlink to another instance's directory, a copy of another
+//! instance's store, the relative root `.`) is never what a Grant is made from.
+//! The signature half of the rule (no root argument, no source reader, no
+//! struct literal, no test constructor) is the `compile_fail` examples on
+//! `read_effective`; this is the behavioural half, committed because it is the
+//! only defence of the rule against a forged store.
+
+#![cfg(unix)]
+
+use std::path::Path;
+
+use chrono::{TimeZone, Utc};
+use eureka_pipeline::Slug;
+use mind_body::control::{BurnRate, ControlWriter, Effective, HeldReason, control_path, read_effective};
+use rust_decimal::Decimal;
+
+/// A name no real install has a store for under the real root.
+const FORGED: &str = "forge-probe-instance";
+const OTHER: &str = "forge-probe-other";
+
+fn release(root: &Path, instance: &str) {
+ let mut writer = ControlWriter::open(control_path(root, &Slug(instance.into())).unwrap()).unwrap();
+ let at = Utc.timestamp_opt(1_800_000_000, 0).unwrap();
+ writer.set_brake(true, at, "forger").unwrap();
+ writer
+ .set_dial(BurnRate { heat: Decimal::ONE, base_cooldown_s: 3600, base_run_usd: Decimal::new(5, 0), set_at: at, set_by: "forger".into() })
+ .unwrap();
+}
+
+fn reads(instance: &str) -> Effective {
+ read_effective(&Slug(instance.into()))
+}
+
+#[test]
+fn no_forged_store_yields_a_grant() {
+ assert_eq!(reads(FORGED), Effective::Held { reason: HeldReason::BrakeAbsent }, "the real root has no store for the probe's name");
+
+ // A released store for the name in a root of the forger's choosing.
+ let tmp = tempfile::tempdir().unwrap();
+ release(tmp.path(), FORGED);
+ assert!(matches!(reads(FORGED), Effective::Held { .. }), "store in a temporary root");
+
+ // A symlink from the name to another instance's released directory.
+ let linked = tempfile::tempdir().unwrap();
+ release(linked.path(), OTHER);
+ std::os::unix::fs::symlink(linked.path().join(OTHER), linked.path().join(FORGED)).unwrap();
+ assert!(matches!(reads(FORGED), Effective::Held { .. }), "symlink to another instance");
+
+ // A copy of another instance's store under the name.
+ let copied = tempfile::tempdir().unwrap();
+ release(copied.path(), OTHER);
+ std::fs::create_dir_all(copied.path().join(FORGED)).unwrap();
+ std::fs::copy(copied.path().join(OTHER).join("control.cc"), copied.path().join(FORGED).join("control.cc")).unwrap();
+ assert!(matches!(reads(FORGED), Effective::Held { .. }), "copy of another instance's store");
+
+ // The relative root '.': the working directory holds /control.cc.
+ let here = tempfile::tempdir().unwrap();
+ release(here.path(), FORGED);
+ let before = std::env::current_dir().unwrap();
+ std::env::set_current_dir(here.path()).unwrap();
+ let relative = reads(FORGED);
+ std::env::set_current_dir(before).unwrap();
+ assert!(matches!(relative, Effective::Held { .. }), "relative root");
+}
diff --git a/crates/mind-body/tests/grant.rs b/crates/mind-body/tests/grant.rs
deleted file mode 100644
index dc4b5ec..0000000
--- a/crates/mind-body/tests/grant.rs
+++ /dev/null
@@ -1,114 +0,0 @@
-//! A Grant is the proof that this instance's own control store released. The
-//! tests are an outside crate's view: the only reader takes a root and an
-//! instance and derives the store path itself, and a launch refuses a Grant
-//! read for another instance before it asks the mind anything.
-
-use std::path::Path;
-
-use anyhow::{Result, anyhow};
-use chrono::{DateTime, TimeZone, Utc};
-use cultnet_rs::Selection;
-use eureka_pipeline::{PipelineDocument, RunTurn, Slug};
-use huginn_mind::{PipelineAdmissionOutcome, PipelineSelectionPage};
-use mind_body::control::{BurnRate, ControlWriter, Effective, HeldReason, control_path, read_effective};
-use mind_body::launch::{Clock, Declined, LaunchOutcome, LaunchRequest, Launcher, Ports, open_and_launch};
-use mind_body::queue::MindPort;
-use rust_decimal::Decimal;
-
-fn slug(name: &str) -> Slug {
- Slug(name.into())
-}
-
-fn release(root: &Path, instance: &Slug) {
- let mut writer = ControlWriter::open(control_path(root, instance).unwrap()).unwrap();
- let at = Utc.timestamp_opt(1_800_000_000, 0).unwrap();
- writer.set_brake(true, at, "op").unwrap();
- writer.set_dial(BurnRate { heat: Decimal::ONE, base_cooldown_s: 3600, base_run_usd: Decimal::new(5, 0), set_at: at, set_by: "op".into() }).unwrap();
-}
-
-/// A mind that answers nothing: a launch that reaches it has gone past the
-/// instance check.
-struct SilentMind(Slug);
-
-impl MindPort for SilentMind {
- fn instance(&self) -> &Slug {
- &self.0
- }
-
- fn query(&self, _selection: &Selection) -> Result {
- Err(anyhow!("the launch asked the mind"))
- }
-
- fn admit(&self, _agent: &str, _session: &str, _documents: Vec) -> Result {
- Err(anyhow!("the launch admitted"))
- }
-}
-
-struct NoUnits;
-
-impl Launcher for NoUnits {
- fn start(&self, _instance: &Slug, _turn: RunTurn) -> Result<()> {
- Err(anyhow!("the launch started a unit"))
- }
-
- fn alive(&self, _instance: &Slug, _turn: RunTurn) -> bool {
- false
- }
-}
-
-struct Now;
-
-impl Clock for Now {
- fn now(&self) -> DateTime {
- Utc.timestamp_opt(1_800_000_100, 0).unwrap()
- }
-}
-
-fn launch_as(mind_instance: &str, grant: mind_body::control::Grant, turn: RunTurn) -> Result {
- let mind = SilentMind(slug(mind_instance));
- let ports = Ports { mind: &mind, launcher: &NoUnits, clock: &Now, host: "host" };
- open_and_launch(&ports, LaunchRequest { turn, claims: vec![], agent: "agent".into(), grant })
-}
-
-#[test]
-fn the_reader_makes_a_grant_for_the_instance_whose_store_it_read() {
- let root = tempfile::tempdir().unwrap();
- release(root.path(), &slug("void"));
- let Effective::Released(grant) = read_effective(root.path(), &slug("void")) else { panic!("void's store is released") };
- assert_eq!(grant.instance(), &slug("void"));
- assert_eq!(grant.run_cap_usd(), Decimal::new(5, 0));
-}
-
-#[test]
-fn another_instances_released_store_yields_no_grant_for_this_one() {
- let root = tempfile::tempdir().unwrap();
- release(root.path(), &slug("void"));
- // The operator holds eureka's brake: eureka has no released store under this root.
- assert_eq!(read_effective(root.path(), &slug("eureka")), Effective::Held { reason: HeldReason::BrakeAbsent });
- // A path-shaped instance cannot reach void's store by walking.
- for walk in ["../void", "void/..", "eureka/../void", "/void"] {
- assert_eq!(read_effective(root.path(), &slug(walk)), Effective::Held { reason: HeldReason::Undecodable }, "{walk}");
- }
-}
-
-#[test]
-fn a_grant_read_for_one_instance_cannot_launch_another() {
- let root = tempfile::tempdir().unwrap();
- release(root.path(), &slug("void"));
- for turn in [RunTurn::SelfRun, RunTurn::PersonaTurn] {
- let Effective::Released(grant) = read_effective(root.path(), &slug("void")) else { panic!("void's store is released") };
- // The mind is eureka's; the silent mind and the unit-less launcher fail loudly if the launch goes on.
- let outcome = launch_as("eureka", grant, turn).unwrap();
- assert_eq!(outcome, LaunchOutcome::Refused(Declined::GrantForOtherInstance), "{turn:?}");
- }
-}
-
-#[test]
-fn the_matching_grant_is_not_stopped_by_the_instance_check() {
- let root = tempfile::tempdir().unwrap();
- release(root.path(), &slug("void"));
- let Effective::Released(grant) = read_effective(root.path(), &slug("void")) else { panic!("void's store is released") };
- // Past the check the silent mind is asked, so the launch errors there.
- let error = launch_as("void", grant, RunTurn::SelfRun).unwrap_err();
- assert!(format!("{error:#}").contains("asked the mind"), "{error:#}");
-}