commit ecd21dccf510d32f0ddfa91a38d72d67ef23c6f6
parent 6fa7d8216f8325f62d64df4786071306456e6af9
Author: Zack Newman <zack@philomathiclife.com>
Date: Sun, 12 Jul 2026 11:10:09 -0600
new lints. move unit tests
Diffstat:
| M | Cargo.toml | | | 6 | ++++-- |
| M | README.md | | | 2 | +- |
| M | src/lib.rs | | | 292 | +------------------------------------------------------------------------------ |
| A | src/tests.rs | | | 308 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
4 files changed, 316 insertions(+), 292 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
name = "priv_sep"
readme = "README.md"
repository = "https://git.philomathiclife.com/repos/priv_sep/"
-rust-version = "1.96.0"
+rust-version = "1.97.0"
version = "3.0.0-alpha.5.1"
[lints.rust]
@@ -28,13 +28,14 @@ unused = { level = "deny", priority = -1 }
warnings = { level = "deny", priority = -1 }
ambiguous-negative-literals = { level = "deny", priority = -1 }
closure-returning-async-block = { level = "deny", priority = -1 }
+dead-code-pub-in-binary = { level = "deny", priority = -1 }
deprecated-in-future = { level = "deny", priority = -1 }
+#deprecated-llvm-intrinsic = { level = "deny", priority = -1 }
deref-into-dyn-supertrait = { level = "deny", priority = -1 }
ffi-unwind-calls = { level = "deny", priority = -1 }
#fuzzy-provenance-casts = { level = "deny", priority = -1 }
impl-trait-redundant-captures = { level = "deny", priority = -1 }
linker-info = { level = "deny", priority = -1 }
-linker-messages = { level = "deny", priority = -1 }
#lossy-provenance-casts = { level = "deny", priority = -1 }
macro-use-extern-crate = { level = "deny", priority = -1 }
meta-variable-misuse = { level = "deny", priority = -1 }
@@ -81,6 +82,7 @@ blanket_clippy_restriction_lints = "allow"
exhaustive_enums = "allow"
exhaustive_structs = "allow"
implicit_return = "allow"
+inline_trait_bounds = "allow"
min_ident_chars = "allow"
missing_trait_methods = "allow"
pub_with_shorthand = "allow"
diff --git a/README.md b/README.md
@@ -161,4 +161,4 @@ documentation can be built.
### Status
The crate is only tested on the `x86_64-unknown-linux-gnu`, `x86_64-unknown-openbsd`, and `aarch64-apple-darwin`
-targets; but it should work on most of the supported platforms.
+targets; but it should work on all of the supported platforms.
diff --git a/src/lib.rs b/src/lib.rs
@@ -158,6 +158,9 @@ mod err;
/// OpenBSD
#[cfg(any(doc, target_os = "openbsd"))]
mod openbsd;
+/// Unit tests.
+#[cfg(test)]
+mod tests;
#[cfg(feature = "std")]
use alloc::borrow::Cow;
#[cfg(feature = "alloc")]
@@ -1290,292 +1293,3 @@ pub fn drop_supplementary_groups() -> Result<(), Errno> {
Err(Errno::last())
}
}
-#[cfg(test)]
-mod tests {
- #[cfg(feature = "std")]
- use super::PrivDropErr;
- use super::{Errno, Gid, SetresidErr, Uid, UserInfo};
- #[cfg(all(feature = "std", target_os = "openbsd"))]
- use super::{Permissions, Promise, Promises};
- #[cfg(feature = "std")]
- use core::net::{Ipv6Addr, SocketAddrV6};
- #[cfg(all(feature = "std", target_os = "openbsd"))]
- extern crate alloc;
- #[cfg(all(feature = "std", target_os = "openbsd"))]
- use alloc::format;
- #[cfg(all(feature = "std", target_os = "openbsd"))]
- use std::io::{self, Write as _};
- #[cfg(feature = "std")]
- use std::{
- fs,
- io::{Error, ErrorKind},
- net::TcpListener,
- };
- use tokio as _;
- #[cfg(feature = "std")]
- const README: &str = "README.md";
- #[test]
- fn getuid() {
- _ = Uid::getuid();
- }
- #[test]
- fn geteuid() {
- _ = Uid::geteuid();
- }
- #[test]
- fn getgid() {
- _ = Gid::getgid();
- }
- #[test]
- fn getegid() {
- _ = Gid::getegid();
- }
- #[test]
- fn setresuid() -> Result<(), Errno> {
- Uid::geteuid().setresuid()
- }
- #[test]
- fn setresgid() -> Result<(), Errno> {
- Gid::getegid().setresgid()
- }
- #[test]
- fn user_info_new() {
- assert_eq!(
- UserInfo::new(c"root"),
- Ok(Some(UserInfo {
- uid: Uid::ROOT,
- gid: Gid(0),
- }))
- );
- }
- #[test]
- fn user_info_setresid() -> Result<(), Errno> {
- UserInfo {
- uid: Uid::geteuid(),
- gid: Gid::getegid(),
- }
- .setresid()
- }
- #[test]
- fn user_info_setresid_if_valid() -> Result<(), SetresidErr> {
- UserInfo {
- uid: Uid::geteuid(),
- gid: Gid::getegid(),
- }
- .setresid_if_valid()
- }
- #[test]
- fn user_info_setresid_if_valid_failure() {
- assert_eq!(
- UserInfo {
- uid: Uid::geteuid(),
- gid: Gid(u32::MAX),
- }
- .setresid_if_valid(),
- Err(SetresidErr::GidMismatch)
- );
- }
- #[cfg(feature = "std")]
- #[test]
- #[ignore = "primarily useful for root and interferes with chroot_drop_priv"]
- fn priv_drop() {
- if Uid::geteuid().is_root() {
- assert!(
- UserInfo::priv_drop(c"nobody", || {
- TcpListener::bind(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 443, 0, 0))
- })
- .is_ok_and(|_| true)
- );
- assert!(
- TcpListener::bind(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 80, 0, 0)).map_or_else(
- |e| matches!(e.kind(), ErrorKind::PermissionDenied),
- |_| false
- )
- );
- } else {
- assert!(
- UserInfo::priv_drop(c"root", || Ok::<_, Error>(()))
- .map_or_else(|e| matches!(e, PrivDropErr::RootEntry), |()| false)
- );
- }
- }
- #[cfg(feature = "std")]
- #[test]
- #[ignore = "primarily useful for root and interferes with priv_drop"]
- fn chroot_drop_priv() {
- if Uid::geteuid().is_root() {
- assert!(
- UserInfo::chroot_then_priv_drop(c"nobody", c"./", false, || {
- TcpListener::bind(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 987, 0, 0))
- })
- .is_ok_and(|_| {
- fs::exists(README).is_ok_and(|exists| {
- exists
- && TcpListener::bind(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 82, 0, 0))
- .map_or_else(
- |e| matches!(e.kind(), ErrorKind::PermissionDenied),
- |_| false,
- )
- })
- })
- );
- }
- }
- #[expect(
- clippy::panic,
- reason = "reasonable to expect files to not exist that need to in order to test pledge and unveil"
- )]
- #[expect(
- clippy::expect_used,
- reason = "kinda reasonable to expect files to exist that mustn't in order to test pledge and unveil"
- )]
- #[cfg(all(feature = "std", target_os = "openbsd"))]
- #[test]
- #[ignore = "interferes with other tests"]
- fn unveil_pledge() {
- const FILE_EXISTS: &str = "/home/zack/foo.txt";
- const FILE_NOT_EXISTS: &str = "/home/zack/aadkjfasj3s23";
- const DIR_NOT_EXISTS: &str = "/home/zack/aadkjfasj3s23/";
- _ = fs::metadata(FILE_EXISTS).unwrap_or_else(|_e| {
- panic!("{FILE_EXISTS} does not exist, so unit testing cannot occur")
- });
- drop(fs::metadata(FILE_NOT_EXISTS).expect_err(
- format!("{FILE_NOT_EXISTS} exists, so unit testing cannot occur").as_str(),
- ));
- drop(
- fs::metadata(DIR_NOT_EXISTS).expect_err(
- format!("{DIR_NOT_EXISTS} exists, so unit testing cannot occur").as_str(),
- ),
- );
- // This tests that a NULL `promise` does nothing.
- assert_eq!(Promises::pledge_none(), Ok(()));
- assert!(writeln!(io::stdout()).is_ok_and(|()| true));
- assert_eq!(Promises::ALL.pledge(), Ok(()));
- // This tests that duplicates are ignored as well as the implementation of PartialEq.
- let mut initial_promises = Promises::new([
- Promise::Stdio,
- Promise::Unveil,
- Promise::Rpath,
- Promise::Stdio,
- ]);
- assert_eq!(initial_promises.len(), 3);
- assert_eq!(
- initial_promises,
- Promises::new([Promise::Rpath, Promise::Stdio, Promise::Unveil])
- );
- // Test retain.
- let mut vals = Promises::new([
- Promise::Audio,
- Promise::Bpf,
- Promise::Chown,
- Promise::Cpath,
- Promise::Error,
- Promise::Exec,
- ]);
- vals.retain([Promise::Error, Promise::Chown]);
- assert_eq!(vals.len(), 2);
- assert!(vals.contains(Promise::Chown));
- assert!(vals.contains(Promise::Error));
- assert_eq!(initial_promises.pledge(), Ok(()));
- // This tests unveil with no permissions.
- assert_eq!(Permissions::NONE.unveil(FILE_EXISTS), Ok(()));
- assert!(fs::metadata(FILE_EXISTS).map_or_else(
- |e| matches!(e.kind(), ErrorKind::PermissionDenied),
- |_| false
- ));
- // This tests unveil with read permissions,
- // and one can unveil more permissions (unlike pledge which can only remove promises).
- assert_eq!(Permissions::READ.unveil(FILE_EXISTS), Ok(()));
- assert!(fs::metadata(FILE_EXISTS).is_ok_and(|_| true));
- // This tests that calls to unveil on missing files don't error.
- assert_eq!(Permissions::NONE.unveil(FILE_NOT_EXISTS), Ok(()));
- // This tests that calls to unveil on missing directories error.
- assert_eq!(Permissions::NONE.unveil(DIR_NOT_EXISTS), Err(Errno::ENOENT));
- // This tests that unveil can no longer be called.
- assert_eq!(Permissions::unveil_no_more(), Ok(()));
- assert_eq!(Permissions::NONE.unveil(FILE_EXISTS), Err(Errno::EPERM));
- assert!(fs::metadata(FILE_EXISTS).is_ok_and(|_| true));
- // The below tests that Promises can only be removed and not added.
- initial_promises.remove_promises([Promise::Unveil]);
- assert_eq!(initial_promises.len(), 2);
- initial_promises.remove(Promise::Rpath);
- assert_eq!(initial_promises.len(), 1);
- initial_promises.remove(Promise::Rpath);
- assert_eq!(initial_promises.len(), 1);
- assert_eq!(initial_promises.pledge(), Ok(()));
- assert!(writeln!(io::stdout()).is_ok_and(|()| true));
- assert_eq!(Promises::new([Promise::Rpath]).pledge(), Err(Errno::EPERM));
- // If the below is uncommented, the program should crash since the above
- // call to pledge no longer allows access to the file system.
- // drop(fs::metadata(FILE_EXISTS));
- }
- #[cfg(all(feature = "std", target_os = "openbsd"))]
- #[test]
- #[ignore = "interferes with other tests when root"]
- fn pledge_inet_drop_priv() {
- if Uid::geteuid().is_root() {
- assert!(
- Promises::new_priv_drop(
- c"nobody",
- [Promise::Inet, Promise::Rpath, Promise::Unveil],
- false,
- || TcpListener::bind(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 47, 0, 0)),
- )
- .is_ok_and(|(_, _)| {
- Permissions::unveil_raw(README, c"r").is_ok_and(|()| {
- fs::exists(README).is_ok_and(|exists| {
- Permissions::NONE.unveil(README).is_ok_and(|()| {
- Promises::pledge_raw(c"inet stdio").is_ok_and(|()| {
- exists
- && TcpListener::bind(SocketAddrV6::new(
- Ipv6Addr::LOCALHOST,
- 792,
- 0,
- 0,
- ))
- .map_or_else(
- |e| matches!(e.kind(), ErrorKind::PermissionDenied),
- |_| false,
- )
- })
- })
- })
- })
- })
- );
- }
- }
- #[cfg(all(feature = "std", target_os = "openbsd"))]
- #[test]
- #[ignore = "interferes with other tests when root"]
- fn inet_chroot_priv_pledge() {
- if Uid::geteuid().is_root() {
- assert!(
- Promises::new_chroot_then_priv_drop(
- c"nobody",
- c"./",
- [Promise::Inet, Promise::Rpath, Promise::Unveil],
- false,
- || TcpListener::bind(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 382, 0, 0))
- )
- .is_ok_and(|(_, mut promises)| Permissions::READ
- .unveil(README)
- .is_ok_and(|()| fs::exists(README).is_ok_and(|exists| Permissions::NONE
- .unveil(README)
- .is_ok_and(|()| promises
- .remove_promises_then_pledge([Promise::Rpath, Promise::Unveil])
- .is_ok_and(|()| exists
- && TcpListener::bind(SocketAddrV6::new(
- Ipv6Addr::LOCALHOST,
- 588,
- 0,
- 0
- ))
- .map_or_else(
- |e| matches!(e.kind(), ErrorKind::PermissionDenied),
- |_| false
- ))))))
- );
- }
- }
-}
diff --git a/src/tests.rs b/src/tests.rs
@@ -0,0 +1,308 @@
+#![cfg_attr(
+ feature = "std",
+ expect(
+ clippy::std_instead_of_core,
+ reason = "false positive until core::io::ErrorKind is stable"
+ )
+)]
+#[cfg(feature = "std")]
+use super::PrivDropErr;
+use super::{Errno, Gid, SetresidErr, Uid, UserInfo};
+#[cfg(all(feature = "std", target_os = "openbsd"))]
+use super::{Permissions, Promise, Promises};
+#[cfg(feature = "std")]
+use core::net::{Ipv6Addr, SocketAddrV6};
+#[cfg(all(feature = "std", target_os = "openbsd"))]
+extern crate alloc;
+#[cfg(all(feature = "std", target_os = "openbsd"))]
+use alloc::format;
+#[cfg(all(feature = "std", target_os = "openbsd"))]
+use std::io::{self, Write as _};
+#[cfg(feature = "std")]
+use std::{
+ fs,
+ io::{Error, ErrorKind},
+ net::TcpListener,
+};
+use tokio as _;
+#[cfg(feature = "std")]
+const README: &str = "README.md";
+#[test]
+fn chdir() {
+ assert_eq!(crate::chdir(c"./"), Ok(()));
+}
+#[cfg(not(target_os = "macos"))]
+#[test]
+fn setgroups() {
+ if Uid::geteuid().is_root() {
+ assert_eq!(crate::setgroups(&[Gid::getegid()]), Ok(()));
+ } else {
+ assert_eq!(crate::setgroups(&[Gid::getegid()]), Err(Errno::EPERM));
+ }
+}
+#[test]
+fn getuid() {
+ _ = Uid::getuid();
+}
+#[test]
+fn geteuid() {
+ _ = Uid::geteuid();
+}
+#[test]
+fn getgid() {
+ _ = Gid::getgid();
+}
+#[test]
+fn getegid() {
+ _ = Gid::getegid();
+}
+#[test]
+fn setresuid() -> Result<(), Errno> {
+ Uid::geteuid().setresuid()
+}
+#[test]
+fn setresgid() -> Result<(), Errno> {
+ Gid::getegid().setresgid()
+}
+#[test]
+fn user_info_new() {
+ assert_eq!(
+ UserInfo::new(c"root"),
+ Ok(Some(UserInfo {
+ uid: Uid::ROOT,
+ gid: Gid(0),
+ }))
+ );
+}
+#[test]
+fn user_info_setresid() -> Result<(), Errno> {
+ UserInfo {
+ uid: Uid::geteuid(),
+ gid: Gid::getegid(),
+ }
+ .setresid()
+}
+#[test]
+fn user_info_setresid_if_valid() -> Result<(), SetresidErr> {
+ UserInfo {
+ uid: Uid::geteuid(),
+ gid: Gid::getegid(),
+ }
+ .setresid_if_valid()
+}
+#[test]
+fn user_info_setresid_if_valid_failure() {
+ assert_eq!(
+ UserInfo {
+ uid: Uid::geteuid(),
+ gid: Gid(u32::MAX),
+ }
+ .setresid_if_valid(),
+ Err(SetresidErr::GidMismatch)
+ );
+}
+#[cfg(feature = "std")]
+#[test]
+#[ignore = "primarily useful for root and interferes with chroot_drop_priv"]
+fn priv_drop() {
+ if Uid::geteuid().is_root() {
+ assert!(
+ UserInfo::priv_drop(c"nobody", || {
+ TcpListener::bind(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 443, 0, 0))
+ })
+ .is_ok_and(|_| true)
+ );
+ assert!(
+ TcpListener::bind(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 80, 0, 0)).map_or_else(
+ |e| matches!(e.kind(), ErrorKind::PermissionDenied),
+ |_| false
+ )
+ );
+ } else {
+ assert!(
+ UserInfo::priv_drop(c"root", || Ok::<_, Error>(()))
+ .map_or_else(|e| matches!(e, PrivDropErr::RootEntry), |()| false)
+ );
+ }
+}
+#[cfg(feature = "std")]
+#[test]
+#[ignore = "primarily useful for root and interferes with priv_drop"]
+fn chroot_drop_priv() {
+ if Uid::geteuid().is_root() {
+ assert!(
+ UserInfo::chroot_then_priv_drop(c"nobody", c"./", false, || {
+ TcpListener::bind(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 987, 0, 0))
+ })
+ .is_ok_and(|_| {
+ fs::exists(README).is_ok_and(|exists| {
+ exists
+ && TcpListener::bind(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 82, 0, 0))
+ .map_or_else(
+ |e| matches!(e.kind(), ErrorKind::PermissionDenied),
+ |_| false,
+ )
+ })
+ })
+ );
+ }
+}
+#[expect(
+ clippy::panic,
+ reason = "reasonable to expect files to not exist that need to in order to test pledge and unveil"
+)]
+#[expect(
+ clippy::expect_used,
+ reason = "kinda reasonable to expect files to exist that mustn't in order to test pledge and unveil"
+)]
+#[cfg(all(feature = "std", target_os = "openbsd"))]
+#[test]
+#[ignore = "interferes with other tests"]
+fn unveil_pledge() {
+ const FILE_EXISTS: &str = "/home/zack/foo.txt";
+ const FILE_NOT_EXISTS: &str = "/home/zack/aadkjfasj3s23";
+ const DIR_NOT_EXISTS: &str = "/home/zack/aadkjfasj3s23/";
+ _ = fs::metadata(FILE_EXISTS)
+ .unwrap_or_else(|_e| panic!("{FILE_EXISTS} does not exist, so unit testing cannot occur"));
+ drop(
+ fs::metadata(FILE_NOT_EXISTS)
+ .expect_err(format!("{FILE_NOT_EXISTS} exists, so unit testing cannot occur").as_str()),
+ );
+ drop(
+ fs::metadata(DIR_NOT_EXISTS)
+ .expect_err(format!("{DIR_NOT_EXISTS} exists, so unit testing cannot occur").as_str()),
+ );
+ // This tests that a NULL `promise` does nothing.
+ assert_eq!(Promises::pledge_none(), Ok(()));
+ assert!(writeln!(io::stdout()).is_ok_and(|()| true));
+ assert_eq!(Promises::ALL.pledge(), Ok(()));
+ // This tests that duplicates are ignored as well as the implementation of PartialEq.
+ let mut initial_promises = Promises::new([
+ Promise::Stdio,
+ Promise::Unveil,
+ Promise::Rpath,
+ Promise::Stdio,
+ ]);
+ assert_eq!(initial_promises.len(), 3);
+ assert_eq!(
+ initial_promises,
+ Promises::new([Promise::Rpath, Promise::Stdio, Promise::Unveil])
+ );
+ // Test retain.
+ let mut vals = Promises::new([
+ Promise::Audio,
+ Promise::Bpf,
+ Promise::Chown,
+ Promise::Cpath,
+ Promise::Error,
+ Promise::Exec,
+ ]);
+ vals.retain([Promise::Error, Promise::Chown]);
+ assert_eq!(vals.len(), 2);
+ assert!(vals.contains(Promise::Chown));
+ assert!(vals.contains(Promise::Error));
+ assert_eq!(initial_promises.pledge(), Ok(()));
+ // This tests unveil with no permissions.
+ assert_eq!(Permissions::NONE.unveil(FILE_EXISTS), Ok(()));
+ assert!(fs::metadata(FILE_EXISTS).map_or_else(
+ |e| matches!(e.kind(), ErrorKind::PermissionDenied),
+ |_| false
+ ));
+ // This tests unveil with read permissions,
+ // and one can unveil more permissions (unlike pledge which can only remove promises).
+ assert_eq!(Permissions::READ.unveil(FILE_EXISTS), Ok(()));
+ assert!(fs::metadata(FILE_EXISTS).is_ok_and(|_| true));
+ // This tests that calls to unveil on missing files don't error.
+ assert_eq!(Permissions::NONE.unveil(FILE_NOT_EXISTS), Ok(()));
+ // This tests that calls to unveil on missing directories error.
+ assert_eq!(Permissions::NONE.unveil(DIR_NOT_EXISTS), Err(Errno::ENOENT));
+ // This tests that unveil can no longer be called.
+ assert_eq!(Permissions::unveil_no_more(), Ok(()));
+ assert_eq!(Permissions::NONE.unveil(FILE_EXISTS), Err(Errno::EPERM));
+ assert!(fs::metadata(FILE_EXISTS).is_ok_and(|_| true));
+ // The below tests that Promises can only be removed and not added.
+ initial_promises.remove_promises([Promise::Unveil]);
+ assert_eq!(initial_promises.len(), 2);
+ initial_promises.remove(Promise::Rpath);
+ assert_eq!(initial_promises.len(), 1);
+ initial_promises.remove(Promise::Rpath);
+ assert_eq!(initial_promises.len(), 1);
+ assert_eq!(initial_promises.pledge(), Ok(()));
+ assert!(writeln!(io::stdout()).is_ok_and(|()| true));
+ assert_eq!(Promises::new([Promise::Rpath]).pledge(), Err(Errno::EPERM));
+ // If the below is uncommented, the program should crash since the above
+ // call to pledge no longer allows access to the file system.
+ // drop(fs::metadata(FILE_EXISTS));
+}
+#[cfg(all(feature = "std", target_os = "openbsd"))]
+#[test]
+#[ignore = "interferes with other tests when root"]
+fn pledge_inet_drop_priv() {
+ if Uid::geteuid().is_root() {
+ assert!(
+ Promises::new_priv_drop(
+ c"nobody",
+ [Promise::Inet, Promise::Rpath, Promise::Unveil],
+ false,
+ || TcpListener::bind(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 47, 0, 0)),
+ )
+ .is_ok_and(|(_, _)| {
+ Permissions::unveil_raw(README, c"r").is_ok_and(|()| {
+ fs::exists(README).is_ok_and(|exists| {
+ Permissions::NONE.unveil(README).is_ok_and(|()| {
+ Promises::pledge_raw(c"inet stdio").is_ok_and(|()| {
+ exists
+ && TcpListener::bind(SocketAddrV6::new(
+ Ipv6Addr::LOCALHOST,
+ 792,
+ 0,
+ 0,
+ ))
+ .map_or_else(
+ |e| matches!(e.kind(), ErrorKind::PermissionDenied),
+ |_| false,
+ )
+ })
+ })
+ })
+ })
+ })
+ );
+ }
+}
+#[cfg(all(feature = "std", target_os = "openbsd"))]
+#[test]
+#[ignore = "interferes with other tests when root"]
+fn inet_chroot_priv_pledge() {
+ if Uid::geteuid().is_root() {
+ assert!(
+ Promises::new_chroot_then_priv_drop(
+ c"nobody",
+ c"./",
+ [Promise::Inet, Promise::Rpath, Promise::Unveil],
+ false,
+ || TcpListener::bind(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 382, 0, 0))
+ )
+ .is_ok_and(
+ |(_, mut promises)| Permissions::READ.unveil(README).is_ok_and(|()| fs::exists(
+ README
+ )
+ .is_ok_and(
+ |exists| Permissions::NONE.unveil(README).is_ok_and(|()| promises
+ .remove_promises_then_pledge([Promise::Rpath, Promise::Unveil])
+ .is_ok_and(|()| exists
+ && TcpListener::bind(SocketAddrV6::new(
+ Ipv6Addr::LOCALHOST,
+ 588,
+ 0,
+ 0
+ ))
+ .map_or_else(
+ |e| matches!(e.kind(), ErrorKind::PermissionDenied),
+ |_| false
+ )))
+ ))
+ )
+ );
+ }
+}