Skip to content

fix(showcase-csp): allow api.github.com so /stats charts populate#52

Merged
LakshmanTurlapati merged 4 commits into
mainfrom
fix/csp-allow-github-api-for-stats
May 15, 2026
Merged

fix(showcase-csp): allow api.github.com so /stats charts populate#52
LakshmanTurlapati merged 4 commits into
mainfrom
fix/csp-allow-github-api-for-stats

Conversation

@LakshmanTurlapati

Copy link
Copy Markdown
Collaborator

Why

The /stats Easter-egg page (showcase/angular/src/app/pages/stats/) was added in quick task 260514-1nv with a client-side GitHubStatsService that fetches 7 endpoints under https://api.github.com/repos/LakshmanTurlapati/FSB/* directly from the browser. The page polls every 5 minutes and renders Chart.js views for cumulative stars, weekly stars, issues, forks, PRs, commits-per-week, and maintenance (releases-per-month).

The page was dark in production. Every chart card was either showing the "Could not load stats" error or the loading skeleton, even though the repo has 66 stars, 17 releases, 4 forks, 50 issues, 47 PRs, and 2300+ commits.

Root cause: the showcase server's CSP header had connect-src 'self', so the browser silently blocked every fetch() to api.github.com. Confirmed via:

$ curl -D - https://full-selfbrowsing.com/stats -o /dev/null | grep content-security
content-security-policy: ...; connect-src 'self'; ...

GitHub's anonymous public-read endpoints return Access-Control-Allow-Origin: *, so once CSP allows the host the browser fetches succeed end-to-end with no server-side proxy needed:

$ curl -I -H "Origin: https://full-selfbrowsing.com" https://api.github.com/repos/LakshmanTurlapati/FSB
access-control-allow-origin: *

What

Three files, ~120 lines of net diff (most of it is the new regression test).

1. showcase/server/server.js — CSP directive

Before:

"connect-src 'self'",

After:

"connect-src 'self' https://api.github.com",

Plus an 8-line explanatory comment block above the SHOWCASE_CSP array naming the consumer so a future tightening doesn't regress this silently:

// connect-src allows api.github.com so the /stats Easter-egg page's
// GitHubStatsService (showcase/angular/src/app/core/stats/github-stats.service.ts)
// can fetch repo metrics directly from the browser. ...

2. tests/showcase-csp-allows-github-api.test.js — new regression test

Node-only, no Express boot — text-parses showcase/server/server.js, locates the connect-src entry in the SHOWCASE_CSP array, and asserts six invariants:

  • showcase/server/server.js exists and is readable
  • SHOWCASE_CSP array literal is present
  • connect-src directive is present
  • connect-src contains 'self'
  • connect-src contains https://api.github.com
  • connect-src does not permit bare * or data: (defense-in-depth)

Standalone runnable: node tests/showcase-csp-allows-github-api.test.js → exits 0 on pass, 1 with diagnostic on fail.

3. package.json — wire into npm test

Single-token insertion of && node tests/showcase-csp-allows-github-api.test.js into scripts.test immediately after the existing showcase-build-smoke.test.js invocation, mirroring that pattern.

What I did NOT change

  • MAX_PAGES = 2 in github-stats.service.ts — verified all 7 endpoints fit comfortably (only commits exceeds 200, but the only chart that consumes commits is a last-12-weeks window which 200 newest commits more than cover; GitHub returns commits newest-first by default).
  • No server-side /api/github-stats/* proxy — the user-facing problem is solved without one, and adding it would be a separate phase (rate-limit headroom + ETag caching is a non-blocking nice-to-have).
  • No new "comments" chart — there is no comments chart in the catalog. "Comments" in the user's request almost certainly meant commits, which already has a view.
  • No changes to /stats Easter-egg crawler invariants: sitemap.xml, llms.txt, llms-full.txt, prerender-routes.txt, and hreflang verifier ROUTE_PATHS all remain free of /stats artifacts (confirmed by the unchanged showcase-build-smoke.test.js Easter-egg invariant — still 134/134 passing).

Test plan

  • New regression test passes standalone (node tests/showcase-csp-allows-github-api.test.js → 6 passed, 0 failed)
  • Full npm test chain green (exit 0)
  • showcase-build-smoke.test.js still 130+ assertions passing (/stats Easter-egg invariant intact)
  • new Function(fs.readFileSync('showcase/server/server.js')) parses (no syntax regressions)
  • Post-merge: Fly.io redeploys → curl -D - https://full-selfbrowsing.com/stats -o /dev/null shows connect-src 'self' https://api.github.com → load /stats in browser → Cumulative-stars chart renders all 66 stars from 2025-08-04 onward; commits / forks / issues / PRs / maintenance views populate within the first 5-minute poll.

Quick task

Tracked at .planning/quick/260514-r6i-fix-csp-on-showcase-server-to-unblock-st/ (PLAN.md + SUMMARY.md).

@LakshmanTurlapati

Copy link
Copy Markdown
Collaborator Author

@codex review

@LakshmanTurlapati LakshmanTurlapati merged commit 51cb77f into main May 15, 2026
8 checks passed
@LakshmanTurlapati LakshmanTurlapati deleted the fix/csp-allow-github-api-for-stats branch May 15, 2026 03:58
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🎉

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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