# Cloudflare Pages response headers for gridticker.com.
#
# GENERATED by tools/build_site.py into site/public/_headers - edit this file,
# then run the generator. Generated for one reason: the demo runs the real
# ticker under a hash-pinned CSP, and a hash somebody has to remember to update
# is a hash that is wrong the first time the app changes.
#
# ONE BLOCK, not two, and that is the whole lesson here. Pages applies EVERY
# matching rule, and a browser given two Content-Security-Policy headers
# enforces their INTERSECTION - so a `/demo/*` block granting a script hash
# under a `/*` block saying `script-src 'none'` grants nothing at all. It fails
# the way CSP always fails: the page loads, draws nothing, and complains only
# to a console nobody has open. Measured by serving site/public with these
# headers and watching the strip stay black.
#
# So the policy below is the site's, and it names the demo's two hashes. It is
# NOT `unsafe-inline`: what may run is exactly the inline blocks of the ticker
# this site ships, byte for byte. Every other page carries no script at all,
# and tools/check_site.py fails one that grows one.
#
# `frame-ancestors 'self'` (and SAMEORIGIN) because the front page and /demo/
# embed the ticker from this same origin; nobody else may frame anything here.
#
# `form-action` names the app because the launch-list form posts there - one
# origin, written out, rather than the wildcard that would let an injected form
# post somewhere else. The route it posts to answers a 303 back here.
/*
  Content-Security-Policy: default-src 'self'; img-src 'self' data:; style-src 'self' 'sha256-1n8JJDDBIIyePUNurg6vQZR8mbiwXBdwwTD/MQv5y7Y='; script-src 'sha256-Z34EU3gA2fnCEpPnWedURKiXSnWn2+g6dElRZo05Z04='; object-src 'none'; base-uri 'none'; form-action 'self' https://app.gridticker.com; frame-ancestors 'self'
  X-Frame-Options: SAMEORIGIN
  X-Content-Type-Options: nosniff
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), geolocation=(), microphone=(), payment=()
