AprilNEA/disclaim

★ 1Forks 0RustGitHub ↗Compare

README

disclaim

Spawn child processes that disclaim the parent's macOS TCC responsibility, so each child is judged under its own code-signing identity.

On macOS, a process spawned the ordinary way inherits its parent's responsibility: the system attributes the child's privacy-permission checks (Accessibility, Input Monitoring, Full Disk Access, …) to the parent app's identity, not the child's. For a helper with its own bundle identity and its own granted permissions — a menu-bar agent, a login item, an updater — that's the wrong identity: the child's permissions look missing because they were granted to it, not to whoever launched it.

disclaim spawns the child with the private libSystem responsibility_spawnattrs_setdisclaim attribute, so macOS evaluates it against its own code signature — the same identity it gets when launchd starts it directly. This is the technique browsers use for their helper processes.

Usage

The API mirrors the relevant subset of std::process::Command:

let mut child = disclaim::Command::new("/Applications/My.app/Contents/Helpers/agent")
    .arg("--background")
    .env("RUST_LOG", "info")
    .spawn()?;
println!("spawned agent pid {}", child.id());

Command supports arg/args, env/envs/env_remove/env_clear, and spawn() -> io::Result<Child>; Child exposes id() and wait(). stdio is inherited.

Platforms

The crate compiles and runs everywhere, so cross-platform code needs no cfg. Disclaiming is a macOS concept; on every other platform Command is a thin pass-through to std::process::Command (there is no responsibility to disclaim).

Scope

This crate exists for the disclaim case, typically a detached helper. It does not expose stdio redirection (pipes/null) — for a fully-managed child with redirected I/O, std::process::Command remains the right tool.

License

MIT OR Apache-2.0.

Contributors

AprilNEA

Issues