Explain why a filesystem operation is denied.
eperm inspects the current process credentials, every traversed path
component, mode bits, native ACLs, mount flags, and relevant platform policy.
It turns a bare Permission denied into a versioned report with one primary
cause, supporting evidence, and explicit unknowns.
$ chmod 000 ./data.json
$ eperm ./data.json --access read
DENIED
operation: read
path: ./data.json
blocked by:
posix_mode: owner permission class has no read bit
...The static MVP supports Linux and macOS. It is conservative by design: eperm
reports inconclusive rather than claiming an allow when an active policy
cannot be evaluated.
The project is not published to crates.io yet. Install the current main
branch with Cargo:
cargo install --git https://github.com/kimurayu45z/eperm --lockedOr build it locally:
git clone https://github.com/kimurayu45z/eperm.git
cd eperm
cargo build --release --locked
./target/release/eperm --helpRust's current stable toolchain is supported. Runtime targets are Linux and macOS.
Choose the operation that should be possible on an existing path:
eperm PATH --access read
eperm PATH --access write
eperm PATH --access execute
eperm DIRECTORY --access list
eperm DIRECTORY --access traverseHuman output is the terminal default. YAML and JSON are typed renderings of the same report and are suitable for issue attachments, scripts, and CI artifacts:
eperm ./data.json --access read --yaml
eperm ./data.json --access read --json
eperm ./data.json --access read --json --output eperm-report.jsonExit status is part of the CLI contract:
| Status | Meaning |
|---|---|
0 |
predicted allow |
1 |
predicted deny |
2 |
inconclusive |
64 |
invalid command-line usage |
70 |
eperm failed to produce the requested report |
Unknown policy layers do not erase an authoritative denial. For example, a
provable mode-bit denial still exits 1 even when SELinux or Landlock needs
deeper analysis.
| Layer | Linux | macOS |
|---|---|---|
| Path traversal and symlink resolution | yes | yes |
| UID/GID and POSIX mode bits | yes | yes |
| Native access ACL | POSIX ACL and mask | ordered allow/deny ACL |
Read-only and noexec mounts |
yes | yes |
| DAC capability overrides | yes | not applicable |
| SELinux, AppArmor, seccomp, Landlock state | conservative probes | not applicable |
| File flags | write reported as not checked | reported as not checked |
| Sandbox, privacy, code policy | not applicable | reported as not checked |
Linux also reports unmodeled active security modules as linux_lsm: unknown.
This avoids false allow conclusions on hosts using BPF LSM, IMA/EVM, IPE,
Smack, TOMOYO, or another policy engine.
eperm diagnoses an explicitly supplied path and access type. It does not run or
trace another command; locating a failed operation remains the responsibility
of that command or a system tracer such as strace or dtruss.
The report describes a snapshot for eperm's own credentials. Filesystem state can race after collection, and policy engines may depend on syscall, process, namespace, entitlement, or audit context that is unavailable without observing the operation.
cargo fmt --all -- --check
cargo test --locked --all-targets
cargo clippy --locked --all-targets --all-features -- -D warnings
RUSTDOCFLAGS="-D warnings" cargo doc --locked --no-depsThe canonical behavior is specified in docs/design.md.
Implementation discussions and rejected alternatives live separately under
docs/meeting-notes/.
Apache-2.0. See LICENSE.