use super::*; use crate::{SyscallOutcome, SyscallResult}; use domain::syscall::Syscall; use types::address::DataRef; use types::bounded::CapSlot; use types::permission::PermissionSet; #[test] fn delegate_without_delegate_permission_fails() { let (mut k, _) = kernel_with_process(); // slot 0 has ProcessCreate cap — no Delegate permission let outcome = k.handle_syscall(Syscall::Delegate { slot: CapSlot::new(0).unwrap(), to_endpoint: CapSlot::new(1).unwrap(), permissions: PermissionSet::empty(), }); assert!(matches!( outcome, SyscallOutcome::Complete(SyscallResult::Error(_)) )); } #[test] fn delegate_with_valid_cap_succeeds() { let (mut k, pid) = kernel_with_process(); // Create a second process to delegate to let target_slot = match k.handle_syscall(Syscall::CreateProcess { create_cap: CapSlot::new(0).unwrap(), image: DataRef::empty(), }) { SyscallOutcome::Complete(SyscallResult::Slot(s)) => s, _ => panic!("expected slot"), }; // Grant a delegatable cap to the caller (endpoint cap with Delegate perm) let ep_id = k.create_endpoint_for_test(); let source_slot = k.grant_cap_for_test( pid, domain::resource::Resource::Endpoint(ep_id), PermissionSet::empty() .with(types::permission::Permission::Read) .with(types::permission::Permission::Delegate), ); let outcome = k.handle_syscall(Syscall::Delegate { slot: source_slot, to_endpoint: target_slot, // using process cap as target identifier permissions: PermissionSet::empty().with(types::permission::Permission::Read), }); assert!(matches!( outcome, SyscallOutcome::Complete(SyscallResult::Slot(_)) )); } // --- Generation-based revocation --- #[test] fn every_representable_slot_is_rejected_not_panicking() { let (mut k, _) = kernel_with_process(); for raw in 1..=CapSlot::MAX { let outcome = k.handle_syscall(Syscall::Send { endpoint: CapSlot::new(raw).unwrap(), message: domain::message::Message::empty(), }); assert!( matches!(outcome, SyscallOutcome::Complete(SyscallResult::Error(_))), "slot {raw} should be an error" ); } }