Files
kyleandClaude Opus 5.5 2b3ae080b4 proto becomes bxcore, the one shared crate (M5b task 00)
Done the way the owner asked and the spike mapped: the crate and the
manifests renamed, then what the build reported fixed. Layers: 138
"proto unresolved" errors across 169 files; cargo fmt reordering
imports; six fixture paths built as strings in brokerd's and bxctl's
tests, which the compiler cannot see, and comments naming
crates/proto/; the crate-dependency check and its self-test. One more
the spike did not reach: a `\nproto =` key inside a printf format in
the self-test, which a word-boundary replacement skips because `n` and
`p` are both word characters.

make gate: gate: ok, 944 tests; no new entry in /tmp.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 01:48:38 -07:00

124 lines
3.3 KiB
Rust

//! The ledger raises a session's state by the stricter of the grant's label and the result's own
//! (M5a spec, section 8). `memoryd` can make a `recall` result untrusted; if the session did not
//! follow, a clean session could recall a tainted note and then write it into `memory.md`. Do not
//! edit.
#[path = "support/build.rs"]
mod build;
#[path = "support/rig.rs"]
mod rig;
#[path = "support/sink.rs"]
mod sink;
#[path = "support/tmp.rs"]
mod tmp;
use brokerd::ledger::Call;
use brokerd::policy::{Label, SessionState};
use build::now;
use bxcore::{AuditEvent, CallId, DataClass, SessionId, ToolResponse};
use rig::Rig;
fn label(class: DataClass, untrusted: bool) -> Label {
Label { class, untrusted }
}
fn call(label: Label) -> Call {
Call {
session: SessionId::new("s1").unwrap(),
call: CallId(1),
decision: 0,
label,
}
}
fn result(label: Label) -> ToolResponse {
ToolResponse::Result {
content: "[1] memory-tainted · note".to_string(),
class: label.class,
untrusted: label.untrusted,
truncated: false,
}
}
fn state(rig: &Rig) -> SessionState {
rig.state().read(&SessionId::new("s1").unwrap()).unwrap()
}
/// The one result record's (class, untrusted, taint_after).
fn recorded(rig: &Rig) -> (DataClass, bool, DataClass) {
match rig.events().as_slice() {
[
AuditEvent::Result {
class,
untrusted,
taint_after,
..
},
] => (*class, *untrusted, *taint_after),
other => panic!("{other:?}"),
}
}
#[test]
fn a_recall_of_a_tainted_note_makes_a_clean_session_untrusted() {
let rig = Rig::new("label-recall");
let ledger = rig.ledger();
// `recall`'s built-in grant labels its results private and trusted; `memoryd` found a
// `memory-tainted` hit and said untrusted.
let found = label(DataClass::Private, true);
let answer = ledger.finish(
&call(label(DataClass::Private, false)),
result(found),
now(),
);
assert_eq!(answer, result(found), "passed on unchanged");
assert_eq!(
state(&rig),
SessionState {
taint: DataClass::Private,
untrusted: true
}
);
assert_eq!(
recorded(&rig),
(DataClass::Private, true, DataClass::Private)
);
}
#[test]
fn a_result_of_a_higher_class_than_its_grant_raises_the_taint() {
let rig = Rig::new("label-class");
let ledger = rig.ledger();
let found = label(DataClass::Secret, false);
ledger.finish(&call(label(DataClass::Public, false)), result(found), now());
assert_eq!(
state(&rig),
SessionState {
taint: DataClass::Secret,
untrusted: false
}
);
assert_eq!(
recorded(&rig),
(DataClass::Secret, false, DataClass::Secret)
);
}
#[test]
fn a_result_laxer_than_its_grant_still_raises_the_state_by_the_grant() {
let rig = Rig::new("label-laxer");
let ledger = rig.ledger();
ledger.finish(
&call(label(DataClass::Secret, true)),
result(label(DataClass::Public, false)),
now(),
);
assert_eq!(
state(&rig),
SessionState {
taint: DataClass::Secret,
untrusted: true
}
);
}