From ed0d04b2d83488643fa5898189dc2672c4ad72c5 Mon Sep 17 00:00:00 2001 From: hass Date: Tue, 27 Oct 2026 21:31:26 -0400 Subject: [PATCH] Keep dashboard entity validation consistent in clean checkouts --- .github/scripts/README.md | 21 +++++++++ .../scripts/dashboard_entity_allowlist.txt | 6 ++- .github/scripts/test_validate_dashboards.py | 43 +++++++++++++++++++ .github/scripts/validate_dashboards.py | 3 +- .github/workflows/config-validation.yml | 3 ++ 5 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 .github/scripts/README.md create mode 100644 .github/scripts/test_validate_dashboards.py diff --git a/.github/scripts/README.md b/.github/scripts/README.md new file mode 100644 index 00000000..74ebbba8 --- /dev/null +++ b/.github/scripts/README.md @@ -0,0 +1,21 @@ +# Repository validation + +Run the same tracked checks used by Config Validation before pushing: + +```powershell +pwsh -NoProfile -File .github/scripts/check_public_repo_safety.ps1 +python -m unittest discover -s .github/scripts -p test_validate_dashboards.py -v +pwsh -NoProfile -File .github/scripts/validate_dashboards.ps1 +pwsh -NoProfile -File .github/scripts/holiday_lighting_coverage.ps1 +node --check .github/scripts/ha_ui_smoke.mjs +``` + +Dashboard entity references must be present in repository configuration or in +`dashboard_entity_allowlist.txt`. For integration, UI-created, or generated entities, +verify the exact entity against Home Assistant before adding its ID to that sorted +list. Keep only IDs already referenced by public dashboards; never export registry +metadata. Unused entries fail validation. + +Private runtime storage provides an additional check of allowlisted entities when +available. It cannot make an otherwise undocumented reference pass locally, so a +clean checkout and a live checkout enforce the same public reference requirement. diff --git a/.github/scripts/dashboard_entity_allowlist.txt b/.github/scripts/dashboard_entity_allowlist.txt index cce4c208..4d0a60d3 100644 --- a/.github/scripts/dashboard_entity_allowlist.txt +++ b/.github/scripts/dashboard_entity_allowlist.txt @@ -2,6 +2,8 @@ # IDs already appear in public dashboards; no private registry metadata is included. # Verified against Home Assistant on 2026-10-24. Four Portainer prune buttons # remain registered but disabled. Keep sorted; stale entries fail validation. +# TV/Roku and Kitchen Show additions verified live on 2026-10-27. +automation.living_room_tv_haven_on_roku_screensaver binary_sensor.bedroom_kiosk_needs_attention binary_sensor.bgw_broadband_connection binary_sensor.docker_host_maintenance_attention @@ -15,6 +17,7 @@ binary_sensor.joanna_memory_index_stale binary_sensor.kiosk_devices_need_attention binary_sensor.kiosk_rain_radar_active binary_sensor.kitchen_kiosk_needs_attention +binary_sensor.kitchen_show_charging binary_sensor.mcu1_gpio10 binary_sensor.mcu1_gpio13 binary_sensor.mcu1_gpio14 @@ -61,6 +64,7 @@ number.sleepnumber_carlo_left_head_position_2 number.sleepnumber_carlo_right_foot_position_2 number.sleepnumber_carlo_right_head_position_2 number.sleepnumber_carlo_stacey_firmness +remote.samsung_q70_series_65 scene.living_room_daytime_cool scene.living_room_evening_amber script.rachio_pause_watering_30 @@ -132,7 +136,6 @@ sensor.juicebox_session_energy_last_known sensor.juicebox_status_last_known sensor.juicebox_temperature_last_known sensor.juicebox_voltage_last_known -sensor.kitchen_show_battery sensor.kitchen_show_last_seen sensor.l10s_vacuum_battery_level sensor.l10s_vacuum_cleaning_count @@ -148,6 +151,7 @@ sensor.l10s_vacuum_total_cleaned_area sensor.living_room_nest_album sensor.living_room_nest_last_screenshot sensor.living_room_nest_uptime +sensor.living_room_ultra_active_app sensor.mariadb_buffer_pool_size sensor.mariadb_buffer_sizes sensor.mariadb_connections diff --git a/.github/scripts/test_validate_dashboards.py b/.github/scripts/test_validate_dashboards.py new file mode 100644 index 00000000..4cec752e --- /dev/null +++ b/.github/scripts/test_validate_dashboards.py @@ -0,0 +1,43 @@ +"""Protect dashboard reference parity between runtime and clean checkouts.""" + +from pathlib import Path +import tempfile +import unittest + +from validate_dashboards import ValidationError, validate_entity_references + + +class EntityReferenceParityTests(unittest.TestCase): + def test_runtime_registry_cannot_hide_missing_public_reference(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + storage = root / "config" / ".storage" + storage.mkdir(parents=True) + (storage / "core.entity_registry").write_text( + '{"entities": [{"entity_id": "sensor.runtime_only"}]}', + encoding="utf-8", + ) + with self.assertRaisesRegex(ValidationError, "unknown static dashboard entity"): + validate_entity_references(root, {"sensor.runtime_only"}) + + def test_public_allowlist_supports_clean_and_runtime_checkouts(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + (root / "config").mkdir() + scripts = root / ".github" / "scripts" + scripts.mkdir(parents=True) + (scripts / "dashboard_entity_allowlist.txt").write_text( + "sensor.runtime_only\n", encoding="utf-8" + ) + validate_entity_references(root, {"sensor.runtime_only"}) + storage = root / "config" / ".storage" + storage.mkdir() + (storage / "core.entity_registry").write_text( + '{"entities": [{"entity_id": "sensor.runtime_only"}]}', + encoding="utf-8", + ) + validate_entity_references(root, {"sensor.runtime_only"}) + + +if __name__ == "__main__": + unittest.main() diff --git a/.github/scripts/validate_dashboards.py b/.github/scripts/validate_dashboards.py index 1a319e33..3764d749 100644 --- a/.github/scripts/validate_dashboards.py +++ b/.github/scripts/validate_dashboards.py @@ -427,7 +427,8 @@ def validate_entity_references(root: Path, references: set[str]) -> None: repository_catalog = repository_entity_catalog(root) live_catalog = live_entity_catalog(root) allowlist = read_entity_allowlist(root) - known = repository_catalog | live_catalog | allowlist + # Private runtime storage must not hide missing references from a clean checkout. + known = repository_catalog | allowlist unknown = sorted(references - known) if unknown: raise ValidationError( diff --git a/.github/workflows/config-validation.yml b/.github/workflows/config-validation.yml index 9dc526e7..3d3995de 100644 --- a/.github/workflows/config-validation.yml +++ b/.github/workflows/config-validation.yml @@ -44,6 +44,9 @@ jobs: - name: Install validation dependencies run: python -m pip install --requirement requirements-dev.txt + - name: Check dashboard validator checkout parity + run: python -m unittest discover -s .github/scripts -p test_validate_dashboards.py -v + - name: Validate dashboard YAML and include graph shell: pwsh run: ./.github/scripts/validate_dashboards.ps1