Application 'linking' done right (#1396)

This commit is contained in:
Sam 2025-08-22 01:17:29 +00:00 committed by GitHub
commit 8df64f8196
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,18 +1,60 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.system;
in
{
config,
lib,
pkgs,
...
}:
{
options = {
};
config = {
system.checks.text = lib.mkAfter ''
ensureAppManagement() {
for appBundle in /Applications/Nix\ Apps/*.app; do
if [[ -d "$appBundle" ]]; then
if ! touch "$appBundle/.DS_Store" &> /dev/null; then
return 1
fi
fi
done
return 0
}
if ! ensureAppManagement; then
if [[ "$(launchctl managername)" != Aqua ]]; then
# It is possible to grant the App Management permission to `sshd-keygen-wrapper`, however
# there are many pitfalls like requiring the primary user to grant the permission and to
# be logged in when `darwin-rebuild` is run over SSH and it will still fail sometimes...
printf >&2 '\e[1;31merror: permission denied when trying to update apps over SSH, aborting activation\e[0m\n'
printf >&2 'Apps could not be updated as `darwin-rebuild` requires Full Disk Access to work over SSH.\n'
printf >&2 'You can either:\n'
printf >&2 '\n'
printf >&2 ' grant Full Disk Access to all programs run over SSH\n'
printf >&2 '\n'
printf >&2 'or\n'
printf >&2 '\n'
printf >&2 ' run `darwin-rebuild` in a graphical session.\n'
printf >&2 '\n'
printf >&2 'The option "Allow full disk access for remote users" can be found by\n'
printf >&2 'navigating to System Settings > General > Sharing > Remote Login\n'
printf >&2 'and then pressing on the i icon next to the switch.\n'
exit 1
else
# The TCC service required to modify notarised app bundles is `kTCCServiceSystemPolicyAppBundles`
# and we can reset it to ensure the user gets another prompt
tccutil reset SystemPolicyAppBundles > /dev/null
if ! ensureAppManagement; then
printf >&2 '\e[1;31merror: permission denied when trying to update apps, aborting activation\e[0m\n'
printf >&2 '`darwin-rebuild` requires permission to update your apps, please accept the notification\n'
printf >&2 'and grant the permission for your terminal emulator in System Settings.\n'
printf >&2 '\n'
printf >&2 'If you did not get a notification, you can navigate to System Settings > Privacy & Security > App Management.\n'
exit 1
fi
fi
fi
'';
system.build.applications = pkgs.buildEnv {
name = "system-applications";
@ -40,13 +82,33 @@ in
fi
''}
if [ ! -e '/Applications/Nix Apps' ] \
|| ourLink '/Applications/Nix Apps'; then
ln -sfn ${cfg.build.applications}/Applications '/Applications/Nix Apps'
else
echo "warning: /Applications/Nix Apps is not owned by nix-darwin, skipping App linking..." >&2
fi
'';
targetFolder='/Applications/Nix Apps'
# Clean up old style symlink to nix store
if [ -e "$targetFolder" ] && ourLink "$targetFolder"; then
rm "$targetFolder"
fi
mkdir -p "$targetFolder"
rsyncFlags=(
# mtime is standardized in the nix store, which would leave only file size to distinguish files.
# Thus we need checksums, despite the speed penalty.
--checksum
# Converts all symlinks pointing outside of the copied tree (thus unsafe) into real files and directories.
# This neatly converts all the symlinks pointing to application bundles in the nix store into
# real directories, without breaking any relative symlinks inside of application bundles.
# This is good enough, because the make-symlinks-relative.sh setup hook converts all $out internal
# symlinks to relative ones.
--copy-unsafe-links
--archive
--delete
--chmod=-w
--no-group
--no-owner
)
${lib.getExe pkgs.rsync} "''${rsyncFlags[@]}" ${config.system.build.applications}/Applications/ "$targetFolder"
'';
};
}