Cache invalidation
Cache invalidation
Wiring the webhook
- Put a random value of at least 32 characters in
PRESS_SECRETwhere your app runs. - In barakoBrew, create a workflow for each content type the site renders, event
Published. A workflow matches one content type, so a site whose posts are anarticletype needs it onarticle, and one onpostnever fires. - Add a Webhook action to each with
Urlset tohttps://your-site/api/revalidateandSecretset to the same value. On a site withsitesconfigured, theSecretis the tenant's key instead, below.
One key per tenant
With sites configured, one app serves many tenants, and each tenant's admin can read and edit its
own workflows. So no tenant is given PRESS_SECRET. Each delivery is verified with a key derived
for the tenant its host resolves to:
key = lowercase hex HMAC-SHA256(PRESS_SECRET, "revalidate." + tenant handle)
A delivery signed with one tenant's key gets a 401 on every other tenant's host, and so does one
signed with PRESS_SECRET itself. Print a tenant's key where PRESS_SECRET (or REVALIDATE_SECRET) is set:
npx barakopress revalidate-key baryo
# or, with no Node:
printf 'revalidate.%s' baryo | openssl dgst -sha256 -hmac "${PRESS_SECRET:-$REVALIDATE_SECRET}" | sed 's/^.* //'
Both read the secret from the environment and print only the key. Paste it into the Secret of that
tenant's Webhook action, with Url on that tenant's domain. A new tenant needs nothing on the
renderer. Changing PRESS_SECRET changes every tenant's key, so each workflow needs its new one.
A site without sites (one build, one site) verifies with PRESS_SECRET itself, as it did with
REVALIDATE_SECRET. Its workflow holds that value, so give it a value no other deployment uses.
Upgrading a multi-tenant site to 0.4.0 is a breaking change. Every tenant's workflow holds
REVALIDATE_SECRET today, and after the upgrade that value verifies for no tenant: deliveries get a
401 and purges stop, with the backstop the only refresh. Before or right after deploying, print each
tenant's key and put it in that tenant's Webhook Secret. Then set a new PRESS_SECRET and print
the keys again, because every tenant admin has seen the old value and could derive any tenant's key
from it.
The barakoCMS webhook body does not name its tenant yet, so the host is what picks the key. Once the body carries the tenant (barakoCMS #868), a delivery whose body names a different tenant than its host resolves to is to be refused.
If your site sets trailingSlash: true, the webhook URL needs the slash. Next redirects
/api/revalidate to /api/revalidate/ with a 308, and barakoCMS does not follow redirects on a
webhook, deliberately: following one was an SSRF hole, because the guard checked only the first hop.
So a URL without the slash gets a 308, the delivery is recorded as failed, it retries five times and
gives up, and the cache is never purged. The site keeps working because of the backstop, so the only
symptom is that publishing feels slow.
barakoCMS refuses to sign a delivery to an http:// URL unless Webhooks:AllowInsecureSignedUrls is
on, which is for a loopback receiver in a lab. In production the URL is https, so this is not in your
way.
Verification follows the recipe in the API's docs/webhooks.md: HMAC-SHA256 over
"<timestamp>.<raw body>", compared in constant time, with a 300 second tolerance so a captured
delivery cannot be replayed later, and each signature honoured once per tenant. An unsigned, missigned or stale
delivery gets a 401. If neither PRESS_SECRET nor REVALIDATE_SECRET is set, or PRESS_SECRET is
shorter than 32 characters, the endpoint answers 503 and purges nothing,
because an open cache-purge endpoint is a free denial of service.