host/taint: honour the ownership carriers on producers only

Neither ownership carrier is a security boundary — both are strings any
unprivileged process can put on its own node — so an unrestricted taint
root is a denial of the whole feature. An unlinked Stream/Input/Audio
named `peerspeak_owned_rogue` is a tainted *reader* (receivers includes
nodes by role, no link required) and an unbounded one, so
propagate_unresolved_owner fails every candidate on the machine closed.

Measured before this change: BASELINE eligible=1 excluded=[] became
WITH IMPOSTOR eligible=0 excluded=[firefox -> unresolved-owner].

Restricting the root to Stream/Output/Audio costs nothing real —
peerspeak only ever tags playback streams — and the AEC's virtual
sink/source is untouched, since it roots on module id, not on this tag.

A tag that is ignored is not silent: misplaced_ownership_tags feeds a
new `ignored_ownership_tags` audit field (omitted when empty), because
the fix *removes* an exclusion, and the two causes of a dropped tag —
a peerspeak tagging bug, or an impersonation attempt — both want seeing.

Codex phase-1 review F2, reproduced live. Round 10, R10-1.
5 new rows, mutation-verified: dropping the role restriction kills both
engine rows, and stubbing the diagnostic kills the third.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-25 20:46:40 -04:00
co-authored by Claude Opus 5
parent 45ca5057f8
commit bf5f2508b8
6 changed files with 252 additions and 6 deletions
+49
View File
@@ -125,6 +125,55 @@ fn the_record_carries_the_complete_candidate_universe() {
assert_eq!(outcome.record.body.excluded_count, 0);
}
/// **R10-1's diagnostic reaches the record.** The engine deliberately ignores
/// an ownership carrier on a non-producer, which means the fix removes an
/// exclusion — so the only way an operator learns a tag was seen and dropped is
/// this field. A matrix row that silently grew an impostor would otherwise read
/// as a clean pass.
#[test]
fn an_ignored_ownership_tag_is_reported_without_excluding_anything() {
let mut graph = Graph::new();
graph.app_node("music", MediaRole::StreamOutput, 100);
let impostor = graph.peerspeak_tagged_node("rogue", MediaRole::StreamInput, 4_242);
let projection = ready(graph.build());
let body = observe(&mut auditor_off(), &projection, 0).record.body;
// The bystander is untouched — the point of the fix.
let (eligible, excluded) = partition(&body);
assert_eq!(eligible, vec!["music"]);
assert!(excluded.is_empty(), "unexpected exclusions: {excluded:?}");
assert!(body.taint.is_empty(), "unexpected taint: {:?}", body.taint);
// ...but the tag is not silent, and the row names the role it appeared on.
assert_eq!(body.ignored_ownership_tags.len(), 1);
let row = &body.ignored_ownership_tags[0];
assert_eq!(row.serial, impostor.serial.0);
assert_eq!(row.role, "stream-input");
assert_eq!(row.name.as_deref(), Some(owned_name("rogue", 4_242).as_str()));
}
/// The common path stays quiet: a correctly tagged peerspeak producer is
/// honoured as a taint root and is *not* reported as a misplaced tag. Without
/// this, a diagnostic that fired on every normal run would be worthless.
#[test]
fn a_correctly_tagged_producer_is_not_reported_as_misplaced() {
let mut graph = Graph::new();
let sink = graph.device_node("speakers", MediaRole::Sink);
let call = graph.peerspeak_node("call", 200);
graph.link(call, sink);
let projection = ready(graph.build());
let body = observe(&mut auditor_off(), &projection, 0).record.body;
assert_eq!(body.excluded_count, 1);
assert!(
body.ignored_ownership_tags.is_empty(),
"honoured tag reported as misplaced: {:?}",
body.ignored_ownership_tags
);
}
/// The fail-closed default asserted at the boundary (impl plan §4, phase 2's
/// "one addition"): nothing in, nothing eligible — and, just as importantly, no
/// panic and no invented row.