Skip to content

Use authenticated brands proxy for repository icons - #937

Open
manuveli wants to merge 1 commit into
hacs:mainfrom
manuveli:fix/brands-proxy-repository-icons
Open

Use authenticated brands proxy for repository icons#937
manuveli wants to merge 1 commit into
hacs:mainfrom
manuveli:fix/brands-proxy-repository-icons

Conversation

@manuveli

@manuveli manuveli commented Apr 18, 2026

Copy link
Copy Markdown

Summary

The HACS dashboard shows "icon not available" for custom integrations that ship inline brand assets (a feature introduced in Home Assistant 2026.3). Root cause is a combination of three things:

  • The homeassistant-frontend submodule is pinned to 3ffbd435 (2025-01-09) — pre-brands-proxy.
  • At that revision, brandsUrl({...}) still returns https://brands.home-assistant.io/_/{domain}/icon.png. That CDN no longer accepts new custom-integration submissions (see the brands-proxy API blog post), so custom-integration icons 404.
  • The dashboard passes useFallback: true — a parameter that has since been removed from upstream BrandsOptions, so a naive submodule bump breaks the TypeScript compile.

Changes

  1. Bump homeassistant-frontend submodule to current upstream master — brings in the new brands-url.ts that returns /api/brands/integration/{domain}/icon.png?token=…, along with fetchAndScheduleBrandsAccessToken / clearBrandsTokenRefresh exports.
  2. Remove useFallback: true from the brandsUrl({...}) call in src/dashboards/hacs-dashboard.ts — the field no longer exists on BrandsOptions. Fallback is now the HA backend's job (stale-while-revalidate through the proxy).
  3. Fetch and schedule the brands access token from the dashboard's bundle. Module-level _brandsAccessToken in brands-url.ts is bundle-scoped, so HACS must populate its own copy; upstream's fetchAndScheduleBrandsAccessToken silently swallows failures on older HA backends. Clear the refresh interval in disconnectedCallback to avoid leaking the setInterval when the panel unmounts.

Fixes hacs/integration#5171
Fixes hacs/integration#5223

A companion PR in the integration repo (hacs/integration) updates the HACS Update entity's entity_picture to use the same authenticated proxy path.

Test plan

  • script/bootstrap && script/build compiles clean (CI via .github/workflows/test.yml).
  • Against HA ≥ 2026.3 with HACS + a custom integration shipping brand/icon.png inline: downloads table shows real icons; rendered <img> has src=/api/brands/integration/{domain}/icon.png?token=….
  • Dark-mode toggle still flows through darkOptimized (filename prefixed with dark_).
  • Against HA < 2026.3 (no brands/access_token WS command): dashboard renders without thrown errors — fetchAndScheduleBrandsAccessToken catches silently.

🤖 Generated with Claude Code

The dashboard constructed icon URLs via the upstream `brandsUrl` helper
at a pinned submodule (3ffbd435, Jan 2025) that predates the
brands-proxy API introduced in HA 2026.3. After upstream rewrote
`brands-url.ts` to return `/api/brands/integration/{domain}/icon.png`
with an access token, custom integrations shipping inline brand assets
no longer render (the legacy CDN no longer accepts new custom
integration submissions).

Bump `homeassistant-frontend` to current master, drop the now-removed
`useFallback` parameter, and fetch/schedule the brands access token
from the dashboard's own bundle (module-level token state is
bundle-scoped, so HACS must populate its own copy). Clear the refresh
interval on disconnect.

Fixes hacs/integration#5171
Fixes hacs/integration#5223

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@manuveli

Copy link
Copy Markdown
Author

@ludeeus sorry for pinging you, but any chance to take a look at this PR and additionally hacs/integration#5228? We would love to have icons back for integrations.

It's fixing hacs/integration#5171 and hacs/integration#5223

Hope to hear from you!

@piitaya

piitaya commented May 22, 2026

Copy link
Copy Markdown

I don't think that will work. If the integration is not installed, the local image will not be available, right?

@ludeeus

ludeeus commented May 22, 2026

Copy link
Copy Markdown
Member

That is correct @piitaya.
There is also a lot that will not work with just bumping the core frontend.
I plan on working on it this weekend.

@manuveli

Copy link
Copy Markdown
Author

You are right, but that's why I have another PR: hacs/integration#5228

@piitaya

piitaya commented May 22, 2026

Copy link
Copy Markdown

The solution I had in mind : a HACS endpoint (/api/hacs/repository/{id}/icon.png) that fetches brand/icon.png via the authenticated GitHub session, caches it under .storage/hacs.icons/. The main issue is how to invalidate the cache.

@manuveli This PR is only about update entities (so, only for installed integration).

@Niek

Niek commented Jun 8, 2026

Copy link
Copy Markdown

It would be great to have this supported soon, since home-assistant/brands is no longer accepting PRs since the brands proxy was added.

joschnurr added a commit to joschnurr/nspanel-ui-config that referenced this pull request Jul 26, 2026
Nachgeprüft statt vermutet, und das Ergebnis widerlegt den bisherigen Text:
ein Eintrag im brands-Repo ist für Custom-Integrationen seit Home Assistant
2026.3 nicht mehr nötig - und nicht mehr möglich. Der Versuch (PR #10853)
wurde binnen einer Minute vom Bot geschlossen: "we no longer accept brand
icons for custom integrations in this repository".

Dass die HACS-Übersicht trotzdem den Platzhalter zeigt, hat einen anderen
Grund: HACS 2.0.5 baut seine Bild-URLs fest gegen brands.home-assistant.io,
statt den lokalen Proxy zu nutzen, den HA für genau diesen Fall anbietet (im
mitgelieferten hacs_frontend nachgesehen: kein einziger Treffer auf
/api/brands). Dort ist das bekannt (hacs/frontend#937,
hacs/integration#5179); von dieser Integration aus lässt sich daran nichts
ändern.

Home Assistant selbst zeigt das Icon längst - der Proxy liefert an der
Produktivinstanz die installierte brand/icon.png md5-identisch aus.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
turbo5000c pushed a commit to turbo5000c/dev-noaa_it_all that referenced this pull request Aug 12, 2026
Restores custom_components/noaa_it_all/brand/ byte-for-byte to its previous
state. The wordmark logos and the dark_icon.png deletion are reverted, and
tests/test_manifest.py goes back to the original pinned dimensions.

Also corrects docs/BRANDING.md, which overstated the problem. The earlier
claim that "no change to this repository can fix it" was wrong, and the
observation that disproves it is simple: other custom integrations do show
icons in the HACS store list. Verified:

  home-assistant/brands/custom_integrations/alarmo      -> exists, icon shows
  home-assistant/brands/custom_integrations/frigate     -> exists, icon shows
  home-assistant/brands/custom_integrations/noaa_it_all -> 404, placeholder

So the store-list icon depends on exactly one thing: whether the domain is in
the home-assistant/brands repo. Ours is not. Being in the HACS default store
is separate and does not grant a CDN icon -- dawg-io/noaa_it_all is already
listed in hacs/default and still shows the placeholder.

That makes submitting custom_integrations/noaa_it_all/ to home-assistant/brands
the actual fix, and worth one attempt. The repo has a workflow that auto-closes
PRs adding new custom-integration folders, but its history shows new entries
still landing through spring 2026, so the outcome is not certain until tried.
Waiting on hacs/frontend#937 is the fallback, not the only option.

The README /blob/ URL fix, its regression test, and the hacs.json tidy are
unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011TA3si1SuRW4W8MD7N9x7a
turbo5000c pushed a commit to turbo5000c/dev-noaa_it_all that referenced this pull request Aug 12, 2026
Removes docs/BRANDING.md and reverts .github/copilot-instructions.md, per the
decision to keep only the README fix. The copilot-instructions changes included
three accurate corrections to a stale "manual trigger only" claim about
hacs-validate.yml, but those are out of scope here and are reverted rather than
carried along; they remain worth a separate change.

test_root_icon_exists lost its pointer to the deleted doc and now states the
reason inline: the root icon.png is the README header source and is not read by
HACS or Home Assistant for store or UI display.

What remains in this branch:

- README.md: the header image used a github.com/.../blob/... URL, which serves
  an HTML page rather than an image, so it rendered broken on GitHub and on the
  HACS repository page (hacs.json sets render_readme). Now points at
  raw.githubusercontent.com.
- tests/test_manifest.py: TestReadmeImages strips fenced code blocks, then fails
  on any github.com /blob/ image URL. Verified by reintroducing the old URL --
  the test fails, and passes again once restored.
- hacs.json: stray tab replaced with spaces.

custom_components/noaa_it_all/brand/ is byte-for-byte identical to main.

For the record, on the HACS store-list icon this branch does not address: it is
served from brands.home-assistant.io, backed by home-assistant/brands, where
noaa_it_all is absent and can no longer be added -- close-new-custom-integrations.yml
(merged 2026-03-03) auto-closes any PR adding a new custom_integrations folder,
confirmed on brands PRs #10952 and #10930 from this month. Integrations that do
show icons were added before that cutoff; open_pico, for instance, landed
2025-10-18. It resolves only when HACS ships hacs/frontend#937.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011TA3si1SuRW4W8MD7N9x7a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants