Skip to content

Commit e8ee29d

Browse files
senamakelmedullabot
andcommitted
test: expose bounded native audit initialization diagnostics
Co-authored-by: Medulla <medulla@tinyhumans.ai>
1 parent 27f357e commit e8ee29d

3 files changed

Lines changed: 108 additions & 2 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ jobs:
116116
117117
$verifiedModule = Join-Path $verifyRoot "$libraryName.dll"
118118
Copy-Item -LiteralPath $module -Destination $verifiedModule
119+
# Diagnose the engine's real pinned ancestor/ACL checks before native
120+
# discovery can hide an asynchronous setup failure behind a timeout.
121+
cargo test --locked -p tinysecurity-audit windows_protected_preprovisioned_namespace_commits_exact_retry -- --nocapture
122+
if ($LASTEXITCODE -ne 0) { throw 'native audit engine initialization diagnostic failed' }
119123
cargo test --locked --package tinysecurity-module --example audit_native_contract -- --nocapture
120124
if ($LASTEXITCODE -ne 0) { throw 'native audit installer regression failed' }
121125
cargo run --locked --package tinysecurity-module --example verify_module -- $verifiedModule

‎crates/tinysecurity-module/examples/audit_native_contract/native.rs‎

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ use std::{
77
path::{Path, PathBuf},
88
time::Duration,
99
};
10-
use tinybus::{Connection, broker::Broker, module::ModuleHost, transport::memory::MemoryBus};
10+
use tinybus::{
11+
Connection,
12+
broker::Broker,
13+
module::{ModuleHost, ModuleState},
14+
transport::memory::MemoryBus,
15+
};
1116
use tinysecurity_bus::{
1217
AccessTier, AuditCorrelation2, AuditedRequest2, CallerContext, Check, CheckAuditedResponse2,
1318
CheckRequest, ModuleConfig, Verdict, names,
@@ -235,6 +240,36 @@ fn request(tail: u64) -> AuditedRequest2<CheckRequest> {
235240
}
236241
}
237242

243+
// Diagnostic categories contain no SDK reason strings or serialized identities.
244+
fn init_category(state: &ModuleState) -> u8 {
245+
match state {
246+
ModuleState::Discovered => 1,
247+
ModuleState::Rejected { .. } => 2,
248+
ModuleState::Unresolved { .. } => 3,
249+
ModuleState::Resolved => 4,
250+
ModuleState::Initializing => 5,
251+
ModuleState::Ready => 6,
252+
ModuleState::Serving => 7,
253+
ModuleState::Faulted { .. } => 8,
254+
ModuleState::Failed { .. } => 9,
255+
ModuleState::Stopped => 10,
256+
ModuleState::Disabled => 11,
257+
}
258+
}
259+
260+
#[cfg(all(windows, test))]
261+
fn engine_category(error: tinysecurity::audit::Error) -> u8 {
262+
use tinysecurity::audit::Error;
263+
match error {
264+
Error::Sanitation => 1,
265+
Error::Conflict => 2,
266+
Error::Permissions => 3,
267+
Error::Busy => 4,
268+
Error::Storage => 5,
269+
Error::Unsupported => 6,
270+
}
271+
}
272+
238273
pub(super) async fn verify(library: &Path) -> std::result::Result<(), Box<dyn std::error::Error>> {
239274
let (_directory, path) = namespace()?;
240275
let bus = MemoryBus::new();
@@ -256,7 +291,20 @@ pub(super) async fn verify(library: &Path) -> std::result::Result<(), Box<dyn st
256291
..Default::default()
257292
})?,
258293
)?;
259-
let module = module_peer(&client).await?;
294+
let module = match module_peer(&client).await {
295+
Ok(module) => module,
296+
Err(error) => {
297+
// The SDK faults asynchronously when setup fails. Observe only its
298+
// typed state; never print the associated reason or module identity.
299+
for module in host.list() {
300+
println!(
301+
"audit-native-init stage=1 category={}",
302+
init_category(&module.state)
303+
);
304+
}
305+
return Err(error);
306+
}
307+
};
260308
let proxy = client.proxy(module.as_str(), names::OBJECT_PATH, names::INTERFACE)?;
261309
assert!(proxy.attestation().await?.is_some());
262310
let first: CheckAuditedResponse2 = proxy

‎crates/tinysecurity-module/examples/audit_native_contract/native_tests.rs‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,57 @@ fn namespace_installer_succeeds_when_set_acl_cmdlet_is_unavailable() {
4848
);
4949
provision_with_script(directory.path(), &script).unwrap();
5050
}
51+
52+
#[test]
53+
fn initialization_diagnostics_discard_reason_strings() {
54+
let reason = "private path or identity".to_owned();
55+
let states = [
56+
ModuleState::Discovered,
57+
ModuleState::Rejected {
58+
reason: reason.clone(),
59+
},
60+
ModuleState::Unresolved {
61+
reason: reason.clone(),
62+
},
63+
ModuleState::Resolved,
64+
ModuleState::Initializing,
65+
ModuleState::Ready,
66+
ModuleState::Serving,
67+
ModuleState::Faulted {
68+
reason: reason.clone(),
69+
},
70+
ModuleState::Failed { reason },
71+
ModuleState::Stopped,
72+
ModuleState::Disabled,
73+
];
74+
for (index, state) in states.iter().enumerate() {
75+
assert_eq!(usize::from(init_category(state)), index + 1);
76+
}
77+
}
78+
79+
#[cfg(windows)]
80+
#[test]
81+
fn installed_namespace_passes_actual_restricted_engine_open() {
82+
use tinysecurity::audit::{Error, JsonlSink};
83+
for (index, error) in [
84+
Error::Sanitation,
85+
Error::Conflict,
86+
Error::Permissions,
87+
Error::Busy,
88+
Error::Storage,
89+
Error::Unsupported,
90+
]
91+
.into_iter()
92+
.enumerate()
93+
{
94+
assert_eq!(usize::from(engine_category(error)), index + 1);
95+
}
96+
let (_directory, path) = namespace().unwrap();
97+
let result = JsonlSink::open(&path, 2048, 3);
98+
let category = result.as_ref().err().copied().map_or(0, engine_category);
99+
println!("audit-native-init stage=2 category={category}");
100+
assert!(
101+
result.is_ok(),
102+
"installed namespace must pass actual restricted engine open"
103+
);
104+
}

0 commit comments

Comments
 (0)