File and directory access checks (since 0.0.69)

fs_readable[group], fs_writable[group] and fs_executable[group] report kernel access checks as 1 allowed / 0 denied for an explicitly configured probe identity. On directories, execute means search/traversal permission. These checks complement fs_mode[group]: a read-write mount can still deny an application access to a path.

Explicit identity, no implicit root probe

dir-groups:
  app:
    paths: [/data, /etc/app/settings.json]
    access:
      uid: 1000
      gid: 1000
      groups: [1000]
monit-docker -c monit-docker.yml stats --rsc 'fs_readable[app]' --rsc 'fs_writable[app]'
monit-docker -c monit-docker.yml cron --state-file /var/lib/monit-docker/state.json \
  --dry-run --cmd-if 'fs_writable[app] == 0 ? restart'

Use numeric container-namespace IDs. groups lists all expected groups, including the primary GID, without duplicates. The probe executes through Docker as uid:gid, then verifies its actual UID, GID and group set. It does not impersonate arbitrary supplementary groups: if Docker supplies different groups, the check is unavailable. Adjust the container configuration/identity rather than accepting a misleading success. Effective and permitted capabilities must both be zero; privileged/root probes with capabilities are rejected.

The group and path identify the sample in JSON and Prometheus. No recursive scan occurs. One bounded exec checks all three rights for each distinct path/identity pair in a cycle. Checks are opt-in and do not run for CPU/memory, disk-space or inode checks alone. python3 and Linux /proc/self/status must be available inside the container. The isolated standard-library probe uses os.access with matching real, effective, saved and filesystem IDs. It deliberately avoids shell test, which may calculate permission bits without accounting for ACLs (notably BusyBox). No Python package is installed by the probe; images without Python report the check as unavailable. Paused containers cannot run probes. A missing/inaccessible path, missing utilities, identity mismatch or malformed response fails collection (code 115); an omitted access identity is a configuration error (110). Unknown results never become 1.

ACL semantics

The probe delegates permission decisions to the operating system rather than decoding ls -l or reproducing ACL precedence in Python. Linux POSIX ACLs managed with setfacl are exercised in integration tests, including named user/group entries, ACL masks and directory search rights. A mask such as mask::r-x can remove writing from a named user:1000:rwx entry. Default ACLs determine inheritance by newly created children; they do not grant current access to the parent directory. Symlinks are followed, and parent-directory search permissions apply. Only existing regular files and directories are checked.

This is an access prediction for the probe, not proof that an application operation will succeed. No file is opened for writing, created, deleted, executed or changed; setfacl is required only in the test fixture. Quotas, free space, immutable/append-only flags, read-only mounts, later permission changes and actual open/create/rename operations can produce different outcomes. For a directory, creating an entry generally requires both write and search permission; deleting also involves the sticky bit and the target’s ownership. An executable bit does not prove that a program or interpreter can run.

SELinux/AppArmor may distinguish the probe executable from the application. Network filesystems (NFSv4 ACLs, SMB server ACLs, credential mapping and caching) are not certified by this check. No NFSv4/SMB ACL parser or full application security-context reproduction is claimed. Test actual application operations separately when those semantics matter. A timeout bounds waiting for the Docker exec response; it does not guarantee cancellation of a kernel-blocked remote filesystem operation. Prefer bounded, local paths for periodic probes.

Rules and metrics

Rules accept == 0, != 0, == 1 or != 1, without units or ranges. Existing directory-group semantics apply: conditions in the same group must match the same path; any matching path satisfies that group. For “all paths must be writable”, alert on fs_writable[app] == 0, rather than interpreting == 1 as a universal assertion. Distinct groups may use different identities for the same path without sharing cached access results.

Prometheus gauges monit_docker_container_fs_readable, monit_docker_container_fs_writable and monit_docker_container_fs_executable carry id, name, group and path labels. Unrequested/unavailable fields are omitted and stale/failed cycles expose no container samples. Rule actions and their results use the existing audit journal; polling does not add audit events for every successful permission check.