Skip to content

Cache-safety headers: mark auth-scoped responses private/no-store (#200) - #201

Merged
silverbackdan merged 1 commit into
mainfrom
feat/200-cache-safety-headers
Jul 17, 2026
Merged

Cache-safety headers: mark auth-scoped responses private/no-store (#200)#201
silverbackdan merged 1 commit into
mainfrom
feat/200-cache-safety-headers

Conversation

@silverbackdan

Copy link
Copy Markdown
Collaborator

Summary

Closes #200.

Route, ResourceManifest and ComponentPosition responses are served from an identical URL but vary by the authenticated session, with no distinguishing URL or query marker a shared cache can key on. This makes that safety decision legible in the response itself.

CacheHeadersEventListener (kernel.response, POST_RESPOND): when the request is authenticated and the resource is in the affected set, override API Platform's default public with Cache-Control: private, no-store. Anonymous / unaffected responses stay publicly cacheable — so the only variant a shared cache stores is the published one, matching Souin's edge rule. no-store is the marker the module's service-worker cacheWillUpdate drops on (components-web-app/cwa-nuxt-module#258).

Decisions

  • No Vary: Cookie — many cookies churn and it would collapse the static cache-hit rate. The existing Vary: path on dynamic positions is untouched.
  • Gate = authenticated token, not cookie presence (a stale cookie on an anon request stays cacheable).
  • Affected set is a configurable allow-listhttp_cache.personalised_resource_classes (default Route, ResourceManifest, ComponentPosition), plus any Publishable resource matched dynamically. Unaffected types (e.g. Layout) stay public even when authenticated.

Tests

  • features/main/cache_headers.feature — authed/anon per resource type + unaffected Layout staying public (8 scenarios).
  • Regressions green: route / component_position / publishable / layout / dynamic_page (132), full PHPUnit suite (534).

Route, ResourceManifest and ComponentPosition responses are served from an
identical URL but vary by the authenticated session, with no distinguishing
URL or query marker for a shared cache to key on.

Add CacheHeadersEventListener (kernel.response, POST_RESPOND): when the request
is authenticated and the resource is in the affected set, override API Platform's
default `public` with `Cache-Control: private, no-store`. Anonymous/unaffected
responses stay publicly cacheable, so the only variant a shared cache stores is
the published one - matching Souin's edge rule. `no-store` is the marker the
module's service-worker cacheWillUpdate drops on (cwa-nuxt-module #258).

- No Vary: Cookie (would collapse static cache-hit rate); existing Vary: path
  on dynamic positions untouched.
- Affected set = configurable http_cache.personalised_resource_classes
  (default Route, ResourceManifest, ComponentPosition) plus any Publishable
  resource, matched dynamically.
- Behat features/main/cache_headers.feature covers authed/anon per resource type
  and an unaffected type (Layout) staying public.
@silverbackdan
silverbackdan merged commit c629748 into main Jul 17, 2026
8 of 11 checks passed
@silverbackdan
silverbackdan deleted the feat/200-cache-safety-headers branch July 17, 2026 19:05
@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 45 lines in your changes missing coverage. Please review.
✅ Project coverage is 26.13%. Comparing base (9d56deb) to head (a9f7b18).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...rc/EventListener/Api/CacheHeadersEventListener.php 0.00% 23 Missing ⚠️
src/DependencyInjection/Configuration.php 0.00% 20 Missing ⚠️
...encyInjection/SilverbackApiComponentsExtension.php 0.00% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main     #201      +/-   ##
============================================
- Coverage     26.29%   26.13%   -0.17%     
- Complexity     2514     2526      +12     
============================================
  Files           252      253       +1     
  Lines          7325     7370      +45     
============================================
  Hits           1926     1926              
- Misses         5399     5444      +45     
Flag Coverage Δ
phpunit 26.13% <0.00%> (-0.17%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

Emit cache-safety headers (Vary + Cache-Control) so responses varying by cookie/path can be safely cached

1 participant