Skip to content

Use the brands proxy for update entity pictures when available - #5524

Open
ReikanYsora wants to merge 1 commit into
hacs:mainfrom
ReikanYsora:brands-proxy-entity-picture
Open

Use the brands proxy for update entity pictures when available#5524
ReikanYsora wants to merge 1 commit into
hacs:mainfrom
ReikanYsora:brands-proxy-entity-picture

Conversation

@ReikanYsora

@ReikanYsora ReikanYsora commented Sep 4, 2026

Copy link
Copy Markdown

Hi :)

Proposed change

Since Home Assistant 2026.3, brand images are served by a local, token-gated proxy at /api/brands/integration/{domain}/{image} (announcement), which resolves custom_components/<domain>/brand/ before falling back to the CDN. HacsRepositoryUpdateEntity.entity_picture still points at the CDN, so update entities of integrations that ship their own brand/ folder show the placeholder image in the updates list.

Core's own UpdateEntity returns /api/brands/integration/{platform}/icon.png by default (update/__init__.py); this makes HACS do the same for the repository's domain when the proxy exists.

This picks up where #5228 and #5339 stopped, and addresses the two points raised in their reviews:

  • Cores without the proxy. The proxy path is only returned when the brands integration is loaded ("brands" in hass.config.components). brands is a bootstrap core integration on every 2026.3+ install (bootstrap.py) and does not exist before it, so this detects the endpoint itself rather than a version number. Older cores keep the CDN URL unchanged.
  • Authentication. The path is returned without a token on purpose, exactly like core's update entities: the frontend appends the rotating brands token to any /api/brands/ URL when it renders an entity picture (state-badge.ts via hass.hassUrl()addBrandsAuth). A token baked into the attribute would expire after an hour.

Feature detection also keeps the existing snapshots identical on both CI legs, since the test harness does not load brands on either.

The dashboard icons are handled separately in hacs/frontend#949.

Verification

  • New test_update_entity_picture, parametrised over both states, asserts the CDN URL without brands and the proxy path with it.
  • Full suite: 431 passed on Home Assistant 2025.3.0 / Python 3.13. No existing snapshot changed.
  • ruff check clean.
  • Checked against a live Home Assistant 2026.9.0 instance running HACS: brands is in hass.config.components, and for two downloaded custom integrations shipping brand/icon.png but absent from home-assistant/brands, /api/brands/integration/{domain}/icon.png serves the real icon (200) both with the bearer token and with the brands/access_token query token, while the current CDN entity_picture answers 200 with the placeholder. Without a token the proxy answers 403.

Related: #5171, #5223, #5228, #5339.

Cheers ;)

ReikanYsora / Jérôme

Home Assistant 2026.3 serves brand images through a local, token-gated
proxy at /api/brands/, which also serves the brand/ assets custom
integrations ship themselves now that home-assistant/brands no longer
accepts images for them.

The update entities still pointed entity_picture at the public CDN, so
integrations that are not grandfathered into the CDN showed the
placeholder image in the updates list.

Return the proxy path when the brands integration is loaded, which is
the case on every core with the proxy, and keep the CDN URL otherwise
so older cores are unaffected. The frontend appends the access token to
/api/brands/ paths itself, exactly as it does for core's own update
entities.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant