Skip to content

Endpoint to purge the rendered HTML cache, for deploys and manual admin purges #243

Description

@silverbackdan

What exists already

Most of this is built. HttpCachePurger (#232 / PR #235) has RENDERED_HTML_TAG = 'cwa-html', a private collectRenderedHtml(), and propagate() which sends the tag to CACHE_URL alongside resource IRIs. The module emits cwa-html on every cacheable page (cwa-nuxt-module#289). A write to a class in http_cache.purge_rendered_html_classes already drops every cached page.

The only thing missing is a way to ask for that purge when there is no write to hang it on.

Why an endpoint, reversing the earlier decision

#232 deliberately rejected a purge endpoint, on the grounds that site-config purging could ride on an existing resource write, so an endpoint would add surface without adding capability. That reasoning held for site config and does not hold for two cases that have since come up:

  1. A front-end-only deploy. The PWA and the API deploy independently. A new build changes every page's /_nuxt asset hashes while changing no resource IRI, so nothing purges and a shared cache serves HTML pointing at files that no longer exist — a blank page, not merely stale content. The PWA cannot know whether the API pod restarted, and with a CDN or a persistent Souin store it would not matter if it did. Asking is the only reliable answer. (Souin's purge endpoint is http://localhost:2019/souin-api/souin, bound inside the API pod, so nothing outside that container can send the BAN itself — see Test email verify process #70.)
  2. A deliberate manual purge, surfaced as an admin action rather than folklore.

The security objection is also weaker than it looked. An admin can already flush the entire HTML cache by editing any site config parameter — that is precisely what purge_rendered_html_classes does. An admin-gated endpoint therefore grants no new capability; it names something that currently only happens as a side effect. The workaround today is "change the site name and change it back", which is worse than an endpoint in every respect.

Shape

  • A single operation that purges the cwa-html tag only — not an arbitrary key, not the whole store. That keeps it unable to touch the API's own resource caches, so the worst case is "every page re-renders once", never "the cache is gone".
  • Needs a public entry point on HttpCachePurger; collectRenderedHtml() is private today and propagate() already does the sending, so the addition is small.
  • Idempotent, returns promptly, does not wait on the cache.
  • ROLE_ADMIN (or whatever publishable.permission resolves to — worth deciding which, consistent with the rest of the publication work).

The part that needs actual care

The deploy credential, not the endpoint. An admin session is interactive and already trusted. A CI token that can call this is a long-lived secret, so it should be scoped to this one operation rather than being a reused admin token. Its blast radius is a cache stampede — every cached page dropping at once and the traffic landing on SSR together — which is recoverable but worth not handing out casually.

Worth considering a short coalescing window server-side (repeated purges within N seconds collapse into one), since the call is cheap to make and expensive to serve.

Acceptance criteria

  • An authenticated operation purges the cwa-html tag and nothing else
  • It cannot be used to purge arbitrary keys or the whole cache
  • Unauthenticated and under-privileged callers are refused
  • Repeated calls are safe, and ideally coalesced
  • Behat covers: purge fires, permission is enforced, and the tag is the only thing sent

Front-end button: components-web-app/cwa-nuxt-module#291 · deploy hook: #70

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions