nix-files/hosts/common/programs/assorted.nix
2024-06-13 01:09:48 +00:00

1211 lines
40 KiB
Nix

{ config, lib, pkgs, ... }:
let
declPackageSet = pkgs: {
packageUnwrapped = null;
suggestedPrograms = pkgs;
};
in
{
sane.programs = {
# PACKAGE SETS
# packages which are unavoidably enabled system-wide by default nixos deployment
# the only real reason to make a proper package set out of these is for documentation
# and to allow them to be easily replaced by sandboxed versions.
nixosBuiltins = {
enableFor.system = lib.mkDefault true;
packageUnwrapped = null;
suggestedPrograms = [ "nixosBuiltinsNet" ]
++ lib.optionals config.networking.wireless.enable [ "nixosBuiltinsWireless" ];
};
nixosBuiltinsNet = declPackageSet [
# from nixos/modules/tasks/network-interfaces.nix
"host"
"iproute2"
"iputils"
"nettools"
];
nixosBuiltinsWireless = declPackageSet [
# from nixos/modules/tasks/network-interfaces.nix
# if config.networking.wireless.enable
"wirelesstools"
"iw"
];
sysadminUtils = declPackageSet [
"ausyscall"
"bridge-utils" # for brctl; debug linux "bridge" inet devices
"btrfs-progs"
"cacert.unbundled" # some services require unbundled /etc/ssl/certs
"cryptsetup"
"ddrescue"
"dig"
"dtc" # device tree [de]compiler
"e2fsprogs" # resize2fs
"efibootmgr"
"errno"
"ethtool"
"fatresize"
"fd"
"file"
"forkstat" # monitor every spawned/forked process
"free"
# "fwupd"
"gawk"
"gdb" # to debug segfaults
"git"
"gptfdisk" # gdisk
"hdparm"
"htop"
"iftop"
"inetutils" # for telnet
"iotop"
"iptables"
# "iw"
"jq"
"killall"
"less"
"lftp"
# "libcap_ng" # for `netcap`
"lsof"
"man-pages"
"man-pages-posix"
# "miniupnpc"
"mmcli"
"nano"
# "ncdu" # ncurses disk usage. doesn't cross compile (zig)
"neovim"
"netcat"
"nethogs"
"nmap"
"nmcli"
"nvme-cli" # nvme
# "openssl"
"parted"
"pciutils"
"powertop"
"ps"
"pstree"
"ripgrep"
"s6-rc" # service manager
"screen"
"smartmontools" # smartctl
# "socat"
"strace"
"subversion"
"tcpdump"
"tree"
"usbutils" # lsusb
"util-linux" # lsblk, lscpu, etc
"valgrind"
"watch"
"wget"
"wirelesstools" # iwlist
# "xq" # jq for XML
# "zfs" # doesn't cross-compile (requires samba)
];
sysadminExtraUtils = declPackageSet [
"backblaze-b2"
"duplicity"
"sane-scripts.backup"
"sqlite" # to debug sqlite3 databases
];
# TODO: split these into smaller groups.
# - moby doesn't want a lot of these.
# - categories like
# - dev?
# - debugging?
consoleUtils = declPackageSet [
"alsaUtils" # for aplay, speaker-test
# "cdrtools"
# "clinfo"
# "dmidecode"
"dtrx" # `unar` alternative, "Do The Right eXtraction"
# "efivar"
"eza" # a better 'ls'
# "flashrom"
"git" # needed as a user package, for config.
# "glib" # for `gsettings`
# "gnupg"
# "gocryptfs"
# "gopass"
# "gopass-jsonapi"
# "helix" # text editor
"htop" # needed as a user package, for ~/.config/htop
# "libsecret" # for managing user keyrings (secret-tool)
# "lm_sensors" # for sensors-detect
# "lshw"
# "memtester"
"mercurial" # hg
"mimeo" # like xdg-open
"neovim" # needed as a user package, for swap persistence
# "nettools"
# "networkmanager"
# "nixos-generators"
"nmon"
# "node2nix"
# "oathToolkit" # for oathtool
"objdump"
# "ponymix"
"pulsemixer"
"python3-repl"
# "python3Packages.eyeD3" # music tagging
"ripgrep" # needed as a user package so that its user-level config file can be installed
"rsync"
"sane-scripts.bittorrent"
"sane-scripts.cli"
# "snapper"
"sops" # for manually viewing secrets; outside `sane-secrets` (TODO: improve sane-secrets!)
"speedtest-cli"
# "ssh-to-age"
"strings"
"sudo"
# "tageditor" # music tagging
# "unar"
"unzip"
"wireguard-tools" # for `wg`
"xdg-utils" # for xdg-open
# "yarn"
"zsh"
];
pcConsoleUtils = declPackageSet [
# "gh" # MS GitHub cli
"nix-index"
"nixpkgs-review"
"sane-scripts.dev"
"sequoia"
];
consoleMediaUtils = declPackageSet [
"blast-ugjka" # cast audio to UPNP/DLNA devices (via pulseaudio sink)
# "catt" # cast videos to chromecast
"ffmpeg"
"go2tv" # cast videos to UPNP/DLNA device (i.e. tv).
"imagemagick"
"sane-cast" # cast videos to UPNP/DLNA, with compatibility
"sox"
"yt-dlp"
];
pcTuiApps = declPackageSet [
"aerc" # email client
# "msmtp" # sendmail
# "offlineimap" # email mailbox sync
# "sfeed" # RSS fetcher
"visidata" # TUI spreadsheet viewer/editor
"w3m" # web browser
];
iphoneUtils = declPackageSet [
# "ifuse"
# "ipfs"
# "libimobiledevice"
"sane-scripts.sync-from-iphone"
];
devPkgs = declPackageSet [
"cargo"
"clang"
"lua"
"nodejs"
"patchelf"
"rustc"
# "tree-sitter"
];
gameApps = declPackageSet [
"animatch"
"gnome-2048"
"gnome.hitori" # like sudoku
];
pcGameApps = declPackageSet [
# "andyetitmoves" # TODO: fix build!
# "armagetronad" # tron/lightcycles; WAN and LAN multiplayer
"celeste64"
# "cutemaze" # meh: trivial maze game; qt6 and keyboard-only
# "cuyo" # trivial puyo-puyo clone
"endless-sky" # space merchantilism/exploration
# "factorio"
"frozen-bubble" # WAN + LAN + 1P/2P bubble bobble
"hase" # WAN worms game
# "hedgewars" # WAN + LAN worms game (5~10 people online at any moment; <https://hedgewars.org>)
# "libremines" # meh: trivial minesweeper; qt6
# "mario0" # SMB + portal
# "mindustry"
# "minesweep-rs" # CLI minesweeper
# "nethack"
# "osu-lazer"
# "pinball" # 3d pinball; kb/mouse. old sourceforge project
# "powermanga" # STYLISH space invaders derivative (keyboard-only)
"shattered-pixel-dungeon" # doesn't cross compile
"space-cadet-pinball" # LMB/RMB controls (bindable though. volume buttons?)
"steam"
"superTux" # keyboard-only controls
"superTuxKart" # poor FPS on pinephone
"tumiki-fighters" # keyboard-only
"vvvvvv" # keyboard-only controls
# "wine"
];
guiApps = declPackageSet [
# package sets
"gameApps"
"guiBaseApps"
];
guiBaseApps = declPackageSet [
# "abaddon" # discord client
"alacritty" # terminal emulator
"calls" # gnome calls (dialer/handler)
"dbus"
"dconf" # required by many packages, but not well-documented :(
# "delfin" # Jellyfin client
"dialect" # language translation
"dino" # XMPP client
"dissent" # Discord client (formerly known as: gtkcord4)
# "emote"
# "evince" # PDF viewer
# "flare-signal" # gtk4 signal client
# "foliate" # e-book reader
"fractal" # matrix client
"g4music" # local music player
# "gnome.cheese"
# "gnome-feeds" # RSS reader (with claimed mobile support)
# "gnome.file-roller"
"gnome.geary" # adaptive e-mail client; uses webkitgtk 4.1
"gnome.gnome-calculator"
"gnome.gnome-calendar"
"gnome.gnome-clocks"
"gnome.gnome-maps"
# "gnome-podcasts"
# "gnome.gnome-system-monitor"
# "gnome.gnome-terminal" # works on phosh
"gnome.gnome-weather"
# "gnome.seahorse" # keyring/secret manager
"gnome-frog" # OCR/QR decoder
"gpodder"
"gst-device-monitor" # for debugging audio/video
# "gthumb"
# "lemoa" # lemmy app
"libcamera" # for `cam` binary (useful for debugging cameras)
"libnotify" # for notify-send; debugging
# "lollypop"
"loupe" # image viewer
"mate.engrampa" # archive manager
"mepo" # maps viewer
"mesa-demos" # for eglinfo, glxinfo & other testing tools
"mpv"
"networkmanagerapplet" # for nm-connection-editor: it's better than not having any gui!
"ntfy-sh" # notification service
# "newsflash" # RSS viewer
"pavucontrol"
"pwvucontrol" # pipewire version of pavu
# "picard" # music tagging
# "libsForQt5.plasmatube" # Youtube player
"signal-desktop"
"snapshot" # camera app
"spot" # Gnome Spotify client
# "sublime-music"
# "tdesktop" # broken on phosh
# "tokodon"
"tuba" # mastodon/pleroma client (stores pw in keyring)
"vulkan-tools" # vulkaninfo
# "whalebird" # pleroma client (Electron). input is broken on phosh.
"xdg-terminal-exec"
"zathura" # PDF/CBZ/ePUB viewer
];
handheldGuiApps = declPackageSet [
# "celluloid" # mpv frontend
# "chatty" # matrix/xmpp/irc client (2023/12/29: disabled because broken cross build)
"cozy" # audiobook player
"epiphany" # gnome's web browser
# "iotas" # note taking app
"komikku"
"koreader"
"megapixels" # camera app
"notejot" # note taking, e.g. shopping list
"planify" # todo-tracker/planner
"portfolio-filemanager"
"tangram" # web browser
"wike" # Wikipedia Reader
"xarchiver" # archiver, backup option for when engrampa UI overflows screen and is unusale (xarchiver UI fails in different ways)
];
pcGuiApps = declPackageSet [
# package sets
"pcGameApps"
"pcTuiApps"
####
"audacity"
# "blanket" # ambient noise generator
"brave" # for the integrated wallet -- as a backup
# "cantata" # music player (mpd frontend)
# "chromium" # chromium takes hours to build. brave is chromium-based, distributed in binary form, so prefer it.
# "cups"
"discord" # x86-only
"electrum"
"element-desktop"
"firefox"
"font-manager"
# "gajim" # XMPP client. cross build tries to import host gobject-introspection types (2023/09/01)
"gimp" # broken on phosh
# "gnome.dconf-editor"
# "gnome.file-roller"
"gnome.gnome-disk-utility"
"gnome.nautilus" # file browser
# "gnome.totem" # video player, supposedly supports UPnP
# "handbrake" #< TODO: fix build
"inkscape"
# "jellyfin-media-player"
"kdenlive"
# "kid3" # audio tagging
"krita"
"libreoffice" # TODO: replace with an office suite that uses saner packaging?
"losslesscut-bin" # x86-only
# "makemkv" # x86-only
# "monero-gui" # x86-only
# "mumble"
# "nheko" # Matrix chat client
# "nicotine-plus" # soulseek client. before re-enabling this make sure it's properly sandboxed!
# "obsidian"
# "openscad" # 3d modeling
# "rhythmbox" # local music player
# "slic3r"
"soundconverter"
"spotify" # x86-only
"tor-browser" # x86-only
# "vlc"
"wireshark" # could maybe ship the cli as sysadmin pkg
# "xterm" # requires Xwayland
# "zecwallet-lite" # x86-only
# "zulip"
];
# INDIVIDUAL PACKAGE DEFINITIONS
alsaUtils.sandbox.method = "landlock";
alsaUtils.sandbox.whitelistAudio = true; #< not strictly necessary?
backblaze-b2 = {};
blanket.buildCost = 1;
blanket.sandbox.method = "bwrap";
blanket.sandbox.whitelistAudio = true;
# blanket.sandbox.whitelistDbus = [ "user" ]; # TODO: untested
blanket.sandbox.whitelistWayland = true;
blueberry.sandbox.method = "bwrap";
blueberry.sandbox.wrapperType = "inplace"; #< various /lib scripts refer to the bins by full path
blueberry.sandbox.whitelistWayland = true;
blueberry.sandbox.extraPaths = [
"/dev/rfkill"
"/run/dbus"
"/sys/class/rfkill"
"/sys/devices"
];
bridge-utils.sandbox.method = "bwrap"; #< bwrap, landlock: both work
bridge-utils.sandbox.net = "all";
btrfs-progs.sandbox.method = "bwrap"; #< bwrap, landlock: both work
btrfs-progs.sandbox.autodetectCliPaths = "existing"; # e.g. `btrfs filesystem df /my/fs`
"cacert.unbundled".sandbox.enable = false;
cargo.persist.byStore.plaintext = [ ".cargo" ];
clang = {};
# cryptsetup: typical use is `cryptsetup open /dev/loopxyz mappedName`, and creates `/dev/mapper/mappedName`
cryptsetup.sandbox.method = "landlock";
cryptsetup.sandbox.extraPaths = [
"/dev/mapper"
"/dev/random"
"/dev/urandom"
"/run" #< it needs the whole directory, at least if using landlock
"/proc"
"/sys/dev/block"
"/sys/devices"
];
cryptsetup.sandbox.capabilities = [ "sys_admin" ];
cryptsetup.sandbox.autodetectCliPaths = "existing";
ddrescue.sandbox.method = "landlock"; # TODO:sandbox: untested
ddrescue.sandbox.autodetectCliPaths = "existingOrParent";
delfin.buildCost = 1;
delfin.sandbox.method = "bwrap";
delfin.sandbox.whitelistAudio = true;
delfin.sandbox.whitelistDbus = [ "user" ]; # else `mpris` plugin crashes the player
delfin.sandbox.whitelistDri = true;
delfin.sandbox.whitelistWayland = true;
delfin.sandbox.net = "clearnet";
# auth token, preferences
delfin.persist.byStore.private = [ ".config/delfin" ];
dig.sandbox.method = "bwrap";
dig.sandbox.net = "all";
# creds, but also 200 MB of node modules, etc
discord.persist.byStore.private = [ ".config/discord" ];
discord.suggestedPrograms = [ "xwayland" ];
discord.sandbox.method = "bwrap";
discord.sandbox.wrapperType = "inplace"; #< /opt-style packaging
discord.sandbox.whitelistAudio = true;
discord.sandbox.whitelistDbus = [ "user" ]; # needed for xdg-open
discord.sandbox.whitelistWayland = true;
discord.sandbox.whitelistX = true;
discord.sandbox.net = "clearnet";
discord.sandbox.extraHomePaths = [
# still needs these paths despite it using the portal's file-chooser :?
"Pictures/cat"
"Pictures/Screenshots"
"Pictures/servo-macros"
"Videos/local"
"Videos/servo"
"tmp"
];
dtc.sandbox.method = "bwrap";
dtc.sandbox.autodetectCliPaths = "existingFile"; # TODO:sandbox: untested
duplicity = {};
e2fsprogs.sandbox.method = "landlock";
e2fsprogs.sandbox.autodetectCliPaths = "existing";
efibootmgr.sandbox.method = "landlock";
efibootmgr.sandbox.extraPaths = [
"/sys/firmware/efi"
];
eg25-control = {};
electrum.buildCost = 1;
electrum.sandbox.method = "bwrap"; # TODO:sandbox: untested
electrum.sandbox.net = "all"; # TODO: probably want to make this run behind a VPN, always
electrum.sandbox.whitelistWayland = true;
electrum.persist.byStore.cryptClearOnBoot = [ ".electrum" ]; #< TODO: use XDG dirs!
endless-sky.buildCost = 1;
endless-sky.persist.byStore.plaintext = [ ".local/share/endless-sky" ];
endless-sky.sandbox.method = "bwrap";
endless-sky.sandbox.whitelistAudio = true;
endless-sky.sandbox.whitelistDri = true;
endless-sky.sandbox.whitelistWayland = true;
# `emote` will show a first-run dialog based on what's in this directory.
# mostly, it just keeps a LRU of previously-used emotes to optimize display order.
# TODO: package [smile](https://github.com/mijorus/smile) for probably a better mobile experience.
emote.persist.byStore.plaintext = [ ".local/share/Emote" ];
ethtool.sandbox.method = "landlock";
ethtool.sandbox.capabilities = [ "net_admin" ];
# eza `ls` replacement
# eza.sandbox.method = "landlock";
eza.sandbox.method = "bwrap"; #< note that bwrap causes `/proc` files to be listed differently (e.g. `eza /proc/sys/net/ipv6/conf/`)
eza.sandbox.autodetectCliPaths = "existing";
eza.sandbox.whitelistPwd = true;
eza.sandbox.extraHomePaths = [
# so that e.g. `eza -l ~` can show which symlink exist
".persist/ephemeral"
".persist/plaintext"
];
fatresize.sandbox.method = "landlock";
fatresize.sandbox.autodetectCliPaths = "parent"; # /dev/sda1 -> needs /dev/sda
fd.sandbox.method = "landlock";
fd.sandbox.autodetectCliPaths = "existing";
fd.sandbox.whitelistPwd = true;
fd.sandbox.extraHomePaths = [
# let it follow symlinks to non-sensitive data
".persist/ephemeral"
".persist/plaintext"
];
ffmpeg.buildCost = 1;
ffmpeg.sandbox.method = "bwrap";
ffmpeg.sandbox.autodetectCliPaths = "existingFileOrParent"; # it outputs uncreated files -> parent dir needs mounting
file.sandbox.method = "bwrap";
file.sandbox.autodetectCliPaths = "existing"; #< file OR directory, yes
findutils.sandbox.method = "bwrap";
findutils.sandbox.autodetectCliPaths = "existing";
findutils.sandbox.whitelistPwd = true;
findutils.sandbox.extraHomePaths = [
# let it follow symlinks to non-sensitive data
".persist/ephemeral"
".persist/plaintext"
];
fluffychat-moby.persist.byStore.plaintext = [ ".local/share/chat.fluffy.fluffychat" ];
font-manager.buildCost = 1;
font-manager.sandbox.method = "bwrap";
font-manager.sandbox.whitelistWayland = true;
font-manager.packageUnwrapped = pkgs.rmDbusServicesInPlace (pkgs.font-manager.override {
# build without the "Google Fonts" integration feature, to save closure / avoid webkitgtk_4_0
withWebkit = false;
});
forkstat.sandbox.method = "landlock"; #< doesn't seem to support bwrap
forkstat.sandbox.isolatePids = false;
forkstat.sandbox.extraPaths = [
"/proc"
];
fuzzel.sandbox.method = "bwrap"; #< landlock nearly works, but unable to open ~/.cache
fuzzel.sandbox.whitelistWayland = true;
fuzzel.persist.byStore.private = [
# this is a file of recent selections
{ path=".cache/fuzzel"; type="file"; }
];
gawk.sandbox.method = "bwrap"; # TODO:sandbox: untested
gawk.sandbox.wrapperType = "inplace"; # /share/gawk libraries refer to /libexec
gawk.sandbox.autodetectCliPaths = "existingFile";
gdb.sandbox.enable = false; # gdb doesn't sandbox well. i don't know how you could.
# gdb.sandbox.method = "landlock"; # permission denied when trying to attach, even as root
gdb.sandbox.autodetectCliPaths = true;
geoclue2-with-demo-agent = {};
# MS GitHub stores auth token in .config
# TODO: we can populate gh's stuff statically; it even lets us use the same oauth across machines
gh.persist.byStore.private = [ ".config/gh" ];
gimp.buildCost = 1;
gimp.sandbox.method = "bwrap";
gimp.sandbox.whitelistX = true;
gimp.sandbox.whitelistWayland = true;
gimp.sandbox.extraHomePaths = [
"Pictures/albums"
"Pictures/cat"
"Pictures/from"
"Pictures/Photos"
"Pictures/Screenshots"
"Pictures/servo-macros"
"dev"
"ref"
"tmp"
];
gimp.sandbox.autodetectCliPaths = true;
gimp.sandbox.extraPaths = [
"/tmp" # "Cannot open display:" if it can't mount /tmp 👀
];
"gnome.gnome-calculator".buildCost = 1;
"gnome.gnome-calculator".sandbox.method = "bwrap";
"gnome.gnome-calculator".sandbox.whitelistWayland = true;
"gnome.gnome-calendar".buildCost = 1;
# gnome-calendar surely has data to persist, but i use it strictly to do date math, not track events.
"gnome.gnome-calendar".sandbox.method = "bwrap";
"gnome.gnome-calendar".sandbox.whitelistWayland = true;
# gnome-disks
"gnome.gnome-disk-utility".buildCost = 1;
"gnome.gnome-disk-utility".sandbox.method = "bwrap";
"gnome.gnome-disk-utility".sandbox.whitelistDbus = [ "system" ];
"gnome.gnome-disk-utility".sandbox.whitelistWayland = true;
"gnome.gnome-disk-utility".sandbox.extraHomePaths = [
"tmp"
"use/iso"
# TODO: probably need /dev and such
];
# seahorse: dump gnome-keyring secrets.
"gnome.seahorse".buildCost = 1;
# N.B.: it can also manage ~/.ssh keys, but i explicitly don't add those to the sandbox for now.
"gnome.seahorse".sandbox.method = "bwrap";
"gnome.seahorse".sandbox.whitelistDbus = [ "user" ];
"gnome.seahorse".sandbox.whitelistWayland = true;
gnome-2048.buildCost = 1;
gnome-2048.sandbox.method = "bwrap";
gnome-2048.sandbox.whitelistWayland = true;
gnome-2048.persist.byStore.plaintext = [ ".local/share/gnome-2048/scores" ];
gnome-frog.buildCost = 1;
gnome-frog.sandbox.method = "bwrap";
gnome-frog.sandbox.whitelistWayland = true;
gnome-frog.sandbox.whitelistDbus = [ "user" ];
gnome-frog.sandbox.extraPaths = [
# needed when processing screenshots
"/tmp"
];
gnome-frog.sandbox.extraHomePaths = [
# for OCR'ing photos from disk
"tmp"
"Pictures/albums"
"Pictures/cat"
"Pictures/from"
"Pictures/Photos"
"Pictures/Screenshots"
"Pictures/servo-macros"
];
gnome-frog.persist.byStore.cryptClearOnBoot = [
".local/share/tessdata" # 15M; dunno what all it is.
];
# hitori rules:
# - click to shade a tile
# 1. no number may appear unshaded more than once in the same row/column
# 2. no two shaded tiles can be direct N/S/E/W neighbors
# - win once (1) and (2) are satisfied
"gnome.hitori".buildCost = 1;
"gnome.hitori".sandbox.method = "bwrap";
"gnome.hitori".sandbox.whitelistWayland = true;
gnugrep.sandbox.method = "bwrap";
gnugrep.sandbox.autodetectCliPaths = "existing";
gnugrep.sandbox.whitelistPwd = true;
gnugrep.sandbox.extraHomePaths = [
# let it follow symlinks to non-sensitive data
".persist/ephemeral"
".persist/plaintext"
];
gnused.sandbox.method = "bwrap";
gnused.sandbox.autodetectCliPaths = "existingFile";
gnused.sandbox.whitelistPwd = true; #< `-i` flag creates a temporary file in pwd (?) and then moves it.
gpsd = {};
gptfdisk.sandbox.method = "landlock";
gptfdisk.sandbox.extraPaths = [
"/dev"
];
gptfdisk.sandbox.autodetectCliPaths = "existing"; #< sometimes you'll use gdisk on a device file.
grim.sandbox.method = "bwrap";
grim.sandbox.autodetectCliPaths = "existingOrParent";
grim.sandbox.whitelistWayland = true;
hase.buildCost = 1;
hase.sandbox.method = "bwrap";
hase.sandbox.net = "clearnet";
hase.sandbox.whitelistAudio = true;
hase.sandbox.whitelistDri = true;
hase.sandbox.whitelistWayland = true;
# hdparm: has to be run as sudo. e.g. `sudo hdparm -i /dev/sda`
hdparm.sandbox.method = "bwrap";
hdparm.sandbox.autodetectCliPaths = "existingFile";
host.sandbox.method = "landlock";
host.sandbox.net = "all"; #< technically, only needs to contact localhost's DNS server
iftop.sandbox.method = "landlock";
iftop.sandbox.capabilities = [ "net_raw" ];
# inetutils: ping, ifconfig, hostname, traceroute, whois, ....
# N.B.: inetutils' `ping` is shadowed by iputils' ping (by nixos, intentionally).
inetutils.sandbox.method = "landlock"; # want to keep the same netns, at least.
inkscape.buildCost = 1;
inkscape.sandbox.method = "bwrap";
inkscape.sandbox.whitelistWayland = true;
inkscape.sandbox.extraHomePaths = [
"Pictures/albums"
"Pictures/cat"
"Pictures/from"
"Pictures/Photos"
"Pictures/Screenshots"
"Pictures/servo-macros"
"dev"
"ref"
"tmp"
];
inkscape.sandbox.autodetectCliPaths = true;
iotop.sandbox.method = "landlock";
iotop.sandbox.extraPaths = [
"/proc"
];
iotop.sandbox.capabilities = [ "net_admin" ];
# provides `ip`, `routel`, `bridge`, others.
# landlock works fine for most of these, but `ip netns exec` wants to attach to an existing namespace
# and that means we can't use ANY sandboxer for it.
iproute2.sandbox.enable = false;
# iproute2.sandbox.net = "all";
# iproute2.sandbox.capabilities = [ "net_admin" ];
# iproute2.sandbox.extraPaths = [
# "/run/netns" # for `ip netns ...` to work, but maybe not needed anymore?
# "/sys/class/net" # for `ip netns ...` to work
# "/var/run/netns"
# ];
iptables.sandbox.method = "landlock";
iptables.sandbox.net = "all";
iptables.sandbox.capabilities = [ "net_admin" ];
# iputils provides `ping` (and arping, clockdiff, tracepath)
iputils.sandbox.method = "landlock";
iputils.sandbox.net = "all";
iputils.sandbox.capabilities = [ "net_raw" ];
iw.sandbox.method = "landlock";
iw.sandbox.net = "all";
iw.sandbox.capabilities = [ "net_admin" ];
jq.sandbox.method = "bwrap";
jq.sandbox.autodetectCliPaths = "existingFile";
killall.sandbox.method = "landlock";
killall.sandbox.extraPaths = [
"/proc"
];
krita.buildCost = 1;
krita.sandbox.method = "bwrap";
krita.sandbox.whitelistWayland = true;
krita.sandbox.autodetectCliPaths = "existing";
krita.sandbox.extraHomePaths = [
"dev"
"Pictures/albums"
"Pictures/cat"
"Pictures/from"
"Pictures/Photos"
"Pictures/Screenshots"
"Pictures/servo-macros"
"ref"
"tmp"
];
libcamera = {};
libcap.sandbox.enable = false; #< for `capsh`, which i use as a sandboxer
libcap_ng.sandbox.enable = false; # there's something about /proc/$pid/fd which breaks `readlink`/stat with every sandbox technique (except capsh-only)
libnotify.sandbox.method = "bwrap";
libnotify.sandbox.whitelistDbus = [ "user" ]; # notify-send
losslesscut-bin.buildCost = 1;
losslesscut-bin.sandbox.method = "bwrap";
losslesscut-bin.sandbox.extraHomePaths = [
"Music"
"Pictures/from" # videos from e.g. mobile phone
"Pictures/servo-macros"
"Videos/local"
"Videos/servo"
"tmp"
];
losslesscut-bin.sandbox.whitelistAudio = true;
losslesscut-bin.sandbox.whitelistDri = true;
losslesscut-bin.sandbox.whitelistWayland = true;
losslesscut-bin.sandbox.whitelistX = true;
lsof.sandbox.method = "capshonly"; # lsof doesn't sandbox under bwrap or even landlock w/ full access to /
lsof.sandbox.capabilities = [ "dac_override" "sys_ptrace" ];
lua = {};
man-pages.sandbox.enable = false;
man-pages-posix.sandbox.enable = false;
mercurial.sandbox.method = "bwrap"; # TODO:sandbox: untested
mercurial.sandbox.net = "clearnet";
mercurial.sandbox.whitelistPwd = true;
mesa-demos = {};
# actual monero blockchain (not wallet/etc; safe to delete, just slow to regenerate)
monero-gui.buildCost = 1;
# XXX: is it really safe to persist this? it doesn't have info that could de-anonymize if captured?
monero-gui.persist.byStore.plaintext = [ ".bitmonero" ];
monero-gui.sandbox.method = "bwrap";
monero-gui.sandbox.net = "all";
monero-gui.sandbox.extraHomePaths = [
"records/finance/cryptocurrencies/monero"
];
mumble.buildCost = 1;
mumble.persist.byStore.private = [ ".local/share/Mumble" ];
nano.sandbox.method = "bwrap";
nano.sandbox.autodetectCliPaths = "existingFileOrParent";
netcat.sandbox.method = "landlock";
netcat.sandbox.net = "all";
nethogs.sandbox.method = "capshonly"; # *partially* works under landlock w/ full access to /
nethogs.sandbox.capabilities = [ "net_admin" "net_raw" ];
# provides `arp`, `hostname`, `route`, `ifconfig`
nettools.sandbox.method = "landlock";
nettools.sandbox.net = "all";
nettools.sandbox.capabilities = [ "net_admin" "net_raw" ];
nettools.sandbox.extraPaths = [
"/proc"
];
networkmanagerapplet.sandbox.method = "bwrap";
networkmanagerapplet.sandbox.whitelistWayland = true;
networkmanagerapplet.sandbox.whitelistDbus = [ "system" ];
nixpkgs-review.sandbox.method = "bwrap";
nixpkgs-review.sandbox.wrapperType = "inplace"; #< shell completions use full paths
nixpkgs-review.sandbox.net = "clearnet";
nixpkgs-review.sandbox.whitelistPwd = true;
nixpkgs-review.sandbox.extraHomePaths = [
".config/git" #< it needs to know commiter name/email, even if not posting
];
nixpkgs-review.sandbox.extraPaths = [
"/nix"
];
nixpkgs-review.persist.byStore.cryptClearOnBoot = [
".cache/nixpkgs-review" #< help it not exhaust / tmpfs
];
nmap.sandbox.method = "bwrap";
nmap.sandbox.net = "all"; # clearnet and lan
nmon.sandbox.method = "landlock";
nmon.sandbox.extraPaths = [
"/proc"
];
nodejs = {};
# `nvme list` only shows results when run as root.
nvme-cli.sandbox.method = "landlock";
nvme-cli.sandbox.extraPaths = [
"/sys/devices"
"/sys/class/nvme"
"/sys/class/nvme-subsystem"
"/sys/class/nvme-generic"
"/dev"
];
nvme-cli.sandbox.capabilities = [ "sys_rawio" ];
# contains only `oathtool`, which i only use for evaluating TOTP codes from CLI/stdin
oath-toolkit.sandbox.method = "bwrap";
# settings (electron app)
obsidian.persist.byStore.plaintext = [ ".config/obsidian" ];
passt.sandbox.enable = false; #< sandbox helper (netns specifically)
parted.sandbox.method = "landlock";
parted.sandbox.extraPaths = [
"/dev"
];
parted.sandbox.autodetectCliPaths = "existing"; #< sometimes you'll use parted on a device file.
patchelf = {};
pavucontrol.sandbox.method = "bwrap";
pavucontrol.sandbox.whitelistAudio = true;
pavucontrol.sandbox.whitelistWayland = true;
pciutils.sandbox.method = "landlock";
pciutils.sandbox.extraPaths = [
"/sys/bus/pci"
"/sys/devices"
];
"perlPackages.FileMimeInfo".sandbox.enable = false; #< TODO: sandbox `mimetype` but not `mimeopen`.
powertop.sandbox.method = "landlock";
powertop.sandbox.capabilities = [ "ipc_lock" "sys_admin" ];
powertop.sandbox.extraPaths = [
"/proc"
"/sys/class"
"/sys/devices"
"/sys/kernel"
];
# procps: free, pgrep, pidof, pkill, ps, pwait, top, uptime, couple others
procps.sandbox.method = "bwrap";
procps.sandbox.isolatePids = false;
pstree.sandbox.method = "landlock";
pstree.sandbox.extraPaths = [
"/proc"
];
pulseaudio = {};
pulsemixer.sandbox.method = "landlock";
pulsemixer.sandbox.whitelistAudio = true;
pwvucontrol.buildCost = 1;
pwvucontrol.sandbox.method = "bwrap";
pwvucontrol.sandbox.whitelistAudio = true;
pwvucontrol.sandbox.whitelistDri = true; # else perf on moby is unusable
pwvucontrol.sandbox.whitelistWayland = true;
python3-repl.packageUnwrapped = pkgs.python3.withPackages (ps: with ps; [
psutil
requests
]);
python3-repl.sandbox.method = "bwrap";
python3-repl.sandbox.net = "clearnet";
python3-repl.sandbox.extraHomePaths = [
"/"
".persist/plaintext"
];
qemu.sandbox.enable = false; #< it's a launcher
qemu.buildCost = 2;
rsync.sandbox.method = "bwrap";
rsync.sandbox.net = "clearnet";
rsync.sandbox.autodetectCliPaths = "existingOrParent";
rustc = {};
sane-cast.sandbox.method = "bwrap";
sane-cast.sandbox.net = "clearnet";
sane-cast.sandbox.autodetectCliPaths = "existingFile";
sane-cast.suggestedPrograms = [ "go2tv" ];
sane-die-with-parent.sandbox.enable = false; #< it's a launcher; can't sandbox
sane-weather.sandbox.method = "bwrap";
sane-weather.sandbox.net = "clearnet";
screen.sandbox.enable = false; #< tty; needs to run anything
sequoia.sandbox.method = "bwrap"; # TODO:sandbox: untested
sequoia.sandbox.whitelistPwd = true;
sequoia.sandbox.autodetectCliPaths = "existingFileOrParent"; # supports `-o <file-to-create>`
shattered-pixel-dungeon.buildCost = 1;
shattered-pixel-dungeon.persist.byStore.plaintext = [ ".local/share/.shatteredpixel/shattered-pixel-dungeon" ];
shattered-pixel-dungeon.sandbox.method = "bwrap";
shattered-pixel-dungeon.sandbox.whitelistAudio = true;
shattered-pixel-dungeon.sandbox.whitelistDri = true;
shattered-pixel-dungeon.sandbox.whitelistWayland = true;
# printer/filament settings
slic3r.buildCost = 1;
slic3r.persist.byStore.plaintext = [ ".Slic3r" ];
slurp.sandbox.method = "bwrap";
slurp.sandbox.whitelistWayland = true;
# use like `sudo smartctl /dev/sda -a`
smartmontools.sandbox.method = "landlock";
smartmontools.sandbox.wrapperType = "inplace"; # ships a script in /etc that calls into its bin
smartmontools.sandbox.autodetectCliPaths = "existing";
smartmontools.sandbox.capabilities = [ "sys_rawio" ];
# snapshot camera, based on libcamera
# TODO: enable dma heaps for more efficient buffer sharing: <https://gitlab.com/postmarketOS/pmaports/-/issues/2789>
snapshot = {};
sops.sandbox.method = "bwrap"; # TODO:sandbox: untested
sops.sandbox.extraHomePaths = [
".config/sops"
"nixos"
# TODO: sops should only need access to knowledge/secrets,
# except that i currently put its .sops.yaml config in the root of ~/knowledge
"knowledge"
];
soundconverter.buildCost = 1;
soundconverter.sandbox.method = "bwrap";
soundconverter.sandbox.whitelistWayland = true;
soundconverter.sandbox.extraHomePaths = [
"Music"
"tmp"
"use"
];
soundconverter.sandbox.extraPaths = [
"/mnt/servo/media/Music"
"/mnt/servo/media/games"
];
soundconverter.sandbox.autodetectCliPaths = "existingOrParent";
sox.sandbox.method = "bwrap";
sox.sandbox.autodetectCliPaths = "existingFileOrParent";
sox.sandbox.whitelistAudio = true;
space-cadet-pinball.buildCost = 1;
space-cadet-pinball.persist.byStore.plaintext = [ ".local/share/SpaceCadetPinball" ];
space-cadet-pinball.sandbox.method = "bwrap";
space-cadet-pinball.sandbox.whitelistAudio = true;
space-cadet-pinball.sandbox.whitelistDri = true;
space-cadet-pinball.sandbox.whitelistWayland = true;
speedtest-cli.sandbox.method = "bwrap";
speedtest-cli.sandbox.net = "all";
sqlite = {};
sshfs-fuse = {}; # used by fs.nix
strace.sandbox.enable = false; #< needs to `exec` its args, and therefore support *anything*
subversion.sandbox.method = "bwrap";
subversion.sandbox.net = "clearnet";
subversion.sandbox.whitelistPwd = true;
sudo.sandbox.enable = false;
superTux.buildCost = 1;
superTux.sandbox.method = "bwrap";
superTux.sandbox.wrapperType = "inplace"; # package Makefile incorrectly installs to $out/games/superTux instead of $out/share/games
superTux.sandbox.whitelistAudio = true;
superTux.sandbox.whitelistDri = true;
superTux.sandbox.whitelistWayland = true;
superTux.persist.byStore.plaintext = [ ".local/share/supertux2" ];
swappy.sandbox.method = "bwrap";
swappy.sandbox.autodetectCliPaths = "existingFileOrParent";
swappy.sandbox.whitelistWayland = true;
tcpdump.sandbox.method = "landlock";
tcpdump.sandbox.net = "all";
tcpdump.sandbox.autodetectCliPaths = "existingFileOrParent";
tcpdump.sandbox.capabilities = [ "net_admin" "net_raw" ];
tdesktop.persist.byStore.private = [ ".local/share/TelegramDesktop" ];
tokodon.buildCost = 1;
tokodon.persist.byStore.private = [ ".cache/KDE/tokodon" ];
tree.sandbox.method = "landlock";
tree.sandbox.autodetectCliPaths = "existing";
tree.sandbox.whitelistPwd = true;
tumiki-fighters.buildCost = 1;
tumiki-fighters.sandbox.method = "bwrap";
tumiki-fighters.sandbox.whitelistAudio = true;
tumiki-fighters.sandbox.whitelistDri = true; #< not strictly necessary, but triples CPU perf
tumiki-fighters.sandbox.whitelistWayland = true;
tumiki-fighters.sandbox.whitelistX = true;
util-linux.sandbox.enable = false; #< TODO: possible to sandbox if i specific a different profile for each of its ~50 binaries
unzip.sandbox.method = "bwrap";
unzip.sandbox.autodetectCliPaths = "existingOrParent";
unzip.sandbox.whitelistPwd = true;
usbutils.sandbox.method = "bwrap"; # breaks `usbhid-dump`, but `lsusb`, `usb-devices` work
usbutils.sandbox.extraPaths = [
"/sys/devices"
"/sys/bus/usb"
];
valgrind.buildCost = 1;
valgrind.sandbox.enable = false; #< it's a launcher: can't sandbox
visidata.sandbox.method = "bwrap"; # TODO:sandbox: untested
visidata.sandbox.autodetectCliPaths = true;
# `vulkaninfo`, `vkcube`
vulkan-tools.sandbox.method = "landlock";
vvvvvv.buildCost = 1;
vvvvvv.sandbox.method = "bwrap";
vvvvvv.sandbox.whitelistAudio = true;
vvvvvv.sandbox.whitelistDri = true; #< playable without, but burns noticably more CPU
vvvvvv.sandbox.whitelistWayland = true;
vvvvvv.persist.byStore.plaintext = [ ".local/share/VVVVVV" ];
w3m.sandbox.method = "bwrap";
w3m.sandbox.net = "all";
w3m.sandbox.extraHomePaths = [
# little-used feature, but you can save web pages :)
"tmp"
];
watch.sandbox.enable = false; #< it executes the command it's given
wdisplays.sandbox.method = "bwrap";
wdisplays.sandbox.whitelistWayland = true;
wget.sandbox.method = "bwrap";
wget.sandbox.net = "all";
wget.sandbox.whitelistPwd = true; # saves to pwd by default
whalebird.buildCost = 1;
whalebird.persist.byStore.private = [ ".config/Whalebird" ];
# `wg`, `wg-quick`
wireguard-tools.sandbox.method = "landlock";
wireguard-tools.sandbox.capabilities = [ "net_admin" ];
# provides `iwconfig`, `iwlist`, `iwpriv`, ...
wirelesstools.sandbox.method = "landlock";
wirelesstools.sandbox.capabilities = [ "net_admin" ];
wl-clipboard.sandbox.method = "bwrap";
wl-clipboard.sandbox.whitelistWayland = true;
wtype = {};
wtype.sandbox.method = "bwrap";
wtype.sandbox.whitelistWayland = true;
xwayland.sandbox.method = "bwrap";
xwayland.sandbox.wrapperType = "inplace"; #< consumers use it as a library (e.g. wlroots)
xwayland.sandbox.whitelistWayland = true; #< just assuming this is needed
xwayland.sandbox.whitelistX = true;
xwayland.sandbox.whitelistDri = true; #< would assume this gives better gfx perf
xterm.sandbox.enable = false; # need to be able to do everything
yarn.persist.byStore.plaintext = [ ".cache/yarn" ];
yt-dlp.sandbox.method = "bwrap"; # TODO:sandbox: untested
yt-dlp.sandbox.net = "all";
yt-dlp.sandbox.whitelistPwd = true; # saves to pwd by default
zfs = {};
};
sane.persist.sys.byStore.plaintext = lib.mkIf config.sane.programs.guiApps.enabled [
# "/var/lib/alsa" # preserve output levels, default devices
{ path = "/var/lib/systemd/backlight"; method = "bind"; } # backlight brightness; bind because systemd T_T
];
systemd.services."systemd-backlight@" = lib.mkIf config.sane.programs.guiApps.enabled {
after = [
"ensure-var-lib-systemd-backlight.service"
];
wants = [
"ensure-var-lib-systemd-backlight.service"
];
};
hardware.opengl = lib.mkIf config.sane.programs.guiApps.enabled ({
enable = true;
driSupport = lib.mkDefault true;
} // (lib.optionalAttrs pkgs.stdenv.isx86_64 {
# for 32 bit applications
# upstream nixpkgs forbids setting driSupport32Bit unless specifically x86_64 (so aarch64 isn't allowed)
driSupport32Bit = lib.mkDefault true;
}));
system.activationScripts.notifyActive = lib.mkIf config.sane.programs.guiApps.enabled {
text = lib.concatStringsSep "\n" ([
''
tryNotifyUser() {
local user="$1"
local new_path="$PATH:${pkgs.sudo}/bin:${pkgs.libnotify}/bin"
local version="$(cat $systemConfig/nixos-version)"
PATH="$new_path" sudo -u "$user" \
env PATH="$new_path" NIXOS_VERSION="$version" /bin/sh -c \
'. $HOME/.profile; dbus_file="$XDG_RUNTIME_DIR/bus"; if [ -z "$DBUS_SESSION_BUS_ADDRESS" ] && [ -e "$dbus_file" ]; then export DBUS_SESSION_BUS_ADDRESS="unix:path=$dbus_file"; fi ; if [ -n "$DBUS_SESSION_BUS_ADDRESS" ]; then notify-send "nixos activated" "version: $NIXOS_VERSION" ; fi'
}
''
] ++ lib.mapAttrsToList
(user: en: lib.optionalString en "tryNotifyUser ${user}")
config.sane.programs.guiApps.enableFor.user
);
};
}