Keep dashboard entity validation consistent in clean checkouts

master
hass 2 weeks ago
parent 1c8f4bce24
commit ed0d04b2d8

@ -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.

@ -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

@ -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()

@ -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(

@ -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

Loading…
Cancel
Save

Powered by TurnKey Linux.