nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
fork

Configure Feed

Select the types of activity you want to include in your feed.

home-assistant: reset permissions when copying default blueprints (#416034)

This fixes the import of backups, that would break when they wanted to
nuke the existing config, because they had to npermission to delete the
default blueprints that were copied without write-permissions from the
nix store.

authored by

Martin Weinelt and committed by
GitHub
0c190d08 7d115cb4

+63 -10
+25 -10
nixos/tests/home-assistant.nix
··· 128 128 ]; 129 129 }; 130 130 lovelaceConfigWritable = true; 131 + }; 131 132 132 - blueprints.automation = [ 133 - (pkgs.fetchurl { 134 - url = "https://github.com/home-assistant/core/raw/2025.1.4/homeassistant/components/automation/blueprints/motion_light.yaml"; 135 - hash = "sha256-4HrDX65ycBMfEY2nZ7A25/d3ZnIHdpHZ+80Cblp+P5w="; 136 - }) 137 - ]; 138 - blueprints.template = [ 139 - "${pkgs.home-assistant.src}/homeassistant/components/template/blueprints/inverted_binary_sensor.yaml" 140 - ]; 133 + # Add blueprints next, because we want to test the installation of the default blueprints first 134 + specialisation.addBlueprints = { 135 + inheritParentConfig = true; 136 + configuration.services.home-assistant = { 137 + blueprints.automation = [ 138 + (pkgs.fetchurl { 139 + url = "https://github.com/home-assistant/core/raw/2025.1.4/homeassistant/components/automation/blueprints/motion_light.yaml"; 140 + hash = "sha256-4HrDX65ycBMfEY2nZ7A25/d3ZnIHdpHZ+80Cblp+P5w="; 141 + }) 142 + ]; 143 + blueprints.template = [ 144 + "${pkgs.home-assistant.src}/homeassistant/components/template/blueprints/inverted_binary_sensor.yaml" 145 + ]; 146 + }; 141 147 }; 142 148 143 149 # Cause a configuration change inside `configuration.yml` and verify that the process is being reloaded. ··· 243 237 with subtest("Check extra components are considered in systemd unit hardening"): 244 238 hass.succeed("systemctl show -p DeviceAllow home-assistant.service | grep -q char-ttyUSB") 245 239 246 - with subtest("Check that blueprints are installed"): 240 + with subtest("Check that default blueprints are copied writable"): 241 + hass.succeed("stat -c '%a' ${configDir}/blueprints/automation/homeassistant | grep 700") 242 + hass.succeed("stat -c '%a' ${configDir}/blueprints/automation/homeassistant/motion_light.yaml | grep 600") 243 + # Delete blueprints, so we can check the declarative setup next 244 + hass.execute("rm -rf ${configDir}/blueprints") 245 + 246 + with subtest("Check that configured blueprints are installed"): 247 + cursor = get_journal_cursor() 248 + hass.succeed("${system}/specialisation/addBlueprints/bin/switch-to-configuration test") 249 + wait_for_homeassistant(cursor) 247 250 hass.succeed("test -L '${configDir}/blueprints/automation/motion_light.yaml'") 248 251 hass.succeed("test -L '${configDir}/blueprints/template/inverted_binary_sensor.yaml'") 249 252
+3
pkgs/servers/home-assistant/default.nix
··· 432 432 # Follow symlinks in /var/lib/hass/www 433 433 ./patches/static-follow-symlinks.patch 434 434 435 + # Copy default blueprints without preserving permissions 436 + ./patches/default-blueprint-permissions.patch 437 + 435 438 # Patch path to ffmpeg binary 436 439 (replaceVars ./patches/ffmpeg-path.patch { 437 440 ffmpeg = "${lib.getExe ffmpeg-headless}";
+35
pkgs/servers/home-assistant/patches/default-blueprint-permissions.patch
··· 1 + commit cca718816f66b0155602c974e6743e8ce49e367b 2 + Author: Martin Weinelt <hexa@darmstadt.ccc.de> 3 + Date: Thu Jun 12 03:37:27 2025 +0200 4 + 5 + blueprints: copy default blueprints w/o permissions 6 + 7 + There is no easy way to achieve this with shutil, because copytree() will 8 + always call copystat() an ruin directory permissions. 9 + 10 + diff --git a/homeassistant/components/blueprint/models.py b/homeassistant/components/blueprint/models.py 11 + index 88052100259..a0b29ed3d01 100644 12 + --- a/homeassistant/components/blueprint/models.py 13 + +++ b/homeassistant/components/blueprint/models.py 14 + @@ -378,9 +378,17 @@ class DomainBlueprints: 15 + if self.blueprint_folder.exists(): 16 + return 17 + 18 + - shutil.copytree( 19 + - integration.file_path / BLUEPRINT_FOLDER, 20 + - self.blueprint_folder / HOMEASSISTANT_DOMAIN, 21 + - ) 22 + + import os 23 + + os.makedirs(self.blueprint_folder / HOMEASSISTANT_DOMAIN) 24 + + 25 + + import subprocess 26 + + subprocess.check_call([ 27 + + "cp", 28 + + "--no-preserve=mode", 29 + + "--no-target-directory", 30 + + "--recursive", 31 + + str(integration.file_path / BLUEPRINT_FOLDER), 32 + + str(self.blueprint_folder / HOMEASSISTANT_DOMAIN), 33 + + ]) 34 + 35 + await self.hass.async_add_executor_job(populate)