# AppArmor deny-list template for a native coding agent.
#
# This ready-to-use example attaches agent-home-guard to Codex. To protect a
# different agent, copy this file, choose a unique profile name, and replace
# /usr/bin/codex with that agent's root-owned executable path.
#
# Install the Codex example with:
#   sudo install -m 0644 contrib/apparmor/agent-home-guard /etc/apparmor.d/agent-home-guard
#   sudo apparmor_parser -r /etc/apparmor.d/agent-home-guard
#
# This template assumes the account's default XDG config/state roots.

abi <abi/4.0>,
include <tunables/global>

profile agent-home-guard /usr/bin/codex flags=(attach_disconnected,mediate_deleted) {
  allow all,

  # Keep all children inside the same profile. Session-manager initialization
  # is no longer exposed through a separately privileged executable.
  /** ix,
  deny change_profile,

  # Authentication keys and credential stores.
  audit deny @{HOME}/.ssh/{,**} mrwkl,
  audit deny @{HOME}/.gnupg/{,**} mrwkl,
  audit deny @{HOME}/.aws/{,**} mrwkl,
  audit deny @{HOME}/.azure/{,**} mrwkl,
  audit deny @{HOME}/.kube/{,**} mrwkl,
  audit deny @{HOME}/.password-store/{,**} mrwkl,
  audit deny @{HOME}/.local/share/password-store/{,**} mrwkl,
  audit deny @{HOME}/.local/share/keyrings/{,**} mrwkl,
  audit deny @{HOME}/.pki/{,**} mrwkl,

  # Service and package-manager credentials.
  audit deny @{HOME}/.config/gcloud/{,**} mrwkl,
  # GitHub CLI configuration is intentionally available to the agent. Keep gh
  # authentication in the desktop keyring; file-backed tokens would no longer
  # be protected by this deny-list profile.
  audit deny @{HOME}/.config/glab-cli/{,**} mrwkl,
  audit deny @{HOME}/.config/op/{,**} mrwkl,
  audit deny @{HOME}/.config/rclone/{,**} mrwkl,
  audit deny @{HOME}/.config/containers/auth.json mrwkl,
  audit deny @{HOME}/.docker/config.json mrwkl,
  audit deny @{HOME}/.netrc mrwkl,
  audit deny @{HOME}/.git-credentials mrwkl,
  audit deny @{HOME}/.npmrc mrwkl,
  audit deny @{HOME}/.pypirc mrwkl,
  audit deny @{HOME}/.pgpass mrwkl,
  audit deny @{HOME}/.my.cnf mrwkl,
  audit deny @{HOME}/.authinfo{,.gpg} mrwkl,

  # Shell and REPL histories commonly contain pasted secrets.
  audit deny @{HOME}/.*history mrwkl,
  audit deny @{HOME}/.local/share/fish/fish_history mrwkl,

  # Browser profiles contain sessions, cookies, and saved credentials.
  audit deny @{HOME}/.mozilla/{,**} mrwkl,
  audit deny @{HOME}/.config/chromium/{,**} mrwkl,
  audit deny @{HOME}/.config/google-chrome{,-beta,-dev}/{,**} mrwkl,
  audit deny @{HOME}/.config/BraveSoftware/{,**} mrwkl,

  # GnuPG and desktop keyrings remain private. The dedicated SSH agent is
  # intentionally available so Git can authenticate without reading .ssh.
  audit deny @{run}user/[0-9]*/gnupg/{,**} mrwkl,
  audit deny @{run}user/[0-9]*/keyring/{,**} mrwkl,

  # Protect the pathname entries for container APIs which could ask an
  # unconfined service to expose protected paths. On kernels which do not
  # mediate pathname socket connect(2) through file rules, this deny-list does
  # not prevent the connection itself; that accepted gap is tracked in LAB-89.
  audit deny @{run}user/[0-9]*/podman/podman.sock mrwkl,
  audit deny @{run}user/[0-9]*/docker.sock mrwkl,
  audit deny /run/docker.sock mrwkl,
  audit deny /var/run/docker.sock mrwkl,

  # Persistent terminal history, the sway-session SQLite database and WAL/SHM
  # sidecars, approved desktop launchers, and per-compositor launch attempts
  # stay outside the agent. The same file rules protect Herdr socket pathnames,
  # but do not claim to mediate pathname socket connect(2) on every kernel.
  audit deny @{HOME}/.config/herdr/{,**} mrwkl,
  # SQLite canonicalizes database paths before opening its WAL/SHM sidecars.
  # Prevent a confined process from bypassing the state-tree deny by renaming
  # one of its writable ancestor directories and substituting a prepared tree.
  audit deny @{HOME}/.local/ w,
  audit deny @{HOME}/.local/state/ w,
  audit deny @{HOME}/.local/state/sway-session/{,**} mrwkl,

  # Protect the Sway socket pathname. Direct Sway IPC can execute commands
  # through the unconfined compositor, but pathname connect mediation is a
  # known LAB-89 gap in this deny-list design.
  audit deny @{run}user/[0-9]*/sway-ipc.*.sock mrwkl,

  # The intended session integration endpoints are owned by the independent
  # sway-session daemon. They accept fixed, schema-validated operations and
  # return no raw registry contents. Only the sway-session daemon hosts them.
  # Pathname mutation protections do not turn this broad deny-list into a
  # complete socket-connect boundary; see the experimental status in README.
  audit deny @{run}user/[0-9]*/sway-session wkl,
  audit deny @{run}user/[0-9]*/sway-session/ wkl,
  audit deny @{run}user/[0-9]*/sway-session/app-operations/{,**} mrwkl,
  audit deny @{run}user/[0-9]*/sway-session/agent-report.sock klm,
  owner @{run}user/[0-9]*/sway-session/agent-report.sock rw,

  # The context-start endpoint accepts only typed context metadata and a
  # numbered empty workspace. It does not accept pane roles or commands.
  audit deny @{run}user/[0-9]*/sway-session/session-start.sock klm,
  owner @{run}user/[0-9]*/sway-session/session-start.sock rw,
}
