Skip to content

feat(admin): surface the CSP report sample/detail in /admin/stats#69

Merged
jdevalk merged 1 commit into
mainfrom
reports-detail-column
Jun 29, 2026
Merged

feat(admin): surface the CSP report sample/detail in /admin/stats#69
jdevalk merged 1 commit into
mainfrom
reports-detail-column

Conversation

@jdevalk

@jdevalk jdevalk commented Jun 29, 2026

Copy link
Copy Markdown
Owner

What

Adds the missing detail column to the /admin/stats recent-reports table — the field that names the rejected Trusted Types policy or the blocked inline snippet for a CSP violation.

Why

While reviewing the CSP logs, the dashboard showed type / path / directive / blocked / disposition but not the one field that disambiguates the report-only trusted-types noise: which policy name was rejected. That lives in the CSP report's sample.

The schema had a blob6 slot (message), but functions/reports.ts populated it only from pick(body, "message", "reason") — and CSP violation bodies carry neither. So the detail was being thrown away at write time; just adding a column would have shown empty cells.

Changes

  • functions/reports.tsblob6 now falls back to sample (Reporting API, camelCase) / script-sample (legacy application/csp-report, kebab). Browsers cap sample themselves; we still truncate to 300. Deprecation/intervention/crash reports keep using message/reason.
  • functions/admin/stats.tsreport_recent selects blob6 AS detail; the recent-reports table renders a detail column. Existing filter data-col indices are unchanged (column appended at the end).
  • src/pages/privacy.astro — discloses the new field (rejected policy name / truncated blocked-content snippet) and bumps the "Last updated" date, per the repo's privacy-honesty rule.

Note

Historical CSP rows will show an empty detail (the sample was never stored); new reports populate it once deployed. No IP, cookies, or query strings are stored — sample is browser-capped and about the page, not the visitor.

Checks

npm run build, astro check (0 errors), eslint (only the pre-existing any warning), and prettier --check all clean.

🤖 Generated with Claude Code

The /admin/stats Reports table showed type, path, directive, blocked, and
disposition but not the one field that names the offending Trusted Types
policy (or the blocked inline snippet): the CSP report's `sample`.

reports.ts only populated blob6 from `message`/`reason`, which CSP violation
bodies never carry — so the detail was being dropped at write time. Pick
`sample` (Reporting API) / `script-sample` (legacy csp-report) as a fallback,
and add a "detail" column to the dashboard's recent-reports table so the
policy name shows up. Privacy policy updated to disclose the new field.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying specification-website with  Cloudflare Pages  Cloudflare Pages

Latest commit: a03ace3
Status:⚡️  Build in progress...

View logs

@jdevalk jdevalk merged commit b99905e into main Jun 29, 2026
7 of 8 checks passed
@jdevalk jdevalk deleted the reports-detail-column branch June 29, 2026 20:13
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.

1 participant