Files
boxmaker/docs/plans/M5a/files/crates/brokerd/tests/ledger_label.rs
T
kyleandClaude Opus 5.5 f389a9a43a M5a plan: tasks 21 and 22, from the device check
21: the ledger raises a session's state by the stricter of the grant's
label and the result's own, so a clean session that recalls a
memory-tainted note becomes untrusted and cannot write it into
memory.md (found on straylight, 2026-09-25). 22: the answers to a note
name notes.md, and for an untrusted add the file that was not changed.
The new given tests are ledger_label.rs and new versions of memoryd's
edit.rs and serve.rs; the old copies are kept as -task06 and -task10. On
a scratch tree at the end of task 20: the named tests fail and then pass,
5 and 4 mutations are caught, and the gate passes with 944 tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 17:55:41 -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 proto::{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
}
);
}