Skip to content

Redesign the site and harden it for 2026 - #115

Open
indiVar0508 wants to merge 2 commits into
masterfrom
redesign/2026-refresh
Open

indiVar0508 wants to merge 2 commits into
masterfrom
redesign/2026-refresh

Conversation

@indiVar0508

@indiVar0508 indiVar0508 commented Nov 9, 2026 •

Copy link
Copy Markdown
Member

Rebuilds the site's theme around the BangPypers brand, replaces the old Mediumish/Bootstrap stack, and fixes several live bugs and security issues. Content (posts, authors, pages) is unchanged apart from the jobs page's embed and the mailing list links.

Before merging: repository settings

  • Settings → Pages → Source: GitHub Actions. Required. The classic Pages builder ignores this repo's Gemfile and can't build the new stylesheet, so a merge without this change won't deploy.
  • Settings → Code security → Private vulnerability reporting: on. The footer's "Report a security issue" link and SECURITY.md rely on it.
  • Verify bangalore.pythonindia.org in the organisation's Pages settings and keep "Enforce HTTPS" on, so nobody else can claim the subdomain.
  • Make the build check required on pull requests.

Bugs fixed on the live site

  • Every tag and year archive link returns 404: the classic builder skips jekyll-archives, and _config.yml used the wrong keys (years/months).
  • Search inserted post text and the search query as raw HTML (DOM XSS). Results are now built with textContent.
  • The RSS feed had an empty title, author "Follow" buttons went nowhere, pages had two h1s, and the mailing list links pointed to the retired Mailman 2 archive.

Design and UX

  • New homepage: when and where to come first (Meetup, Discord, Luma, mailing list), then recent write-ups, community posts and ways to take part.
  • Logo marks taken from bangpypers/assets, navy #002750 and yellow #FFCA00 palette, Anek Latin and Source Serif 4.
  • Light and dark themes. The site follows the system setting, and a header button remembers the reader's choice; Giscus comments follow it.
  • Posts get reading time, author cards, tags and share links. The blog and archives are grouped by year with a jump-to-year bar. New 404 page.
  • Accessibility: skip link, landmarks, one h1 per page, one link per card, visible focus, reduced motion respected.
  • Homepage CSS and JS went from about 205 KB to about 18 KB gzipped. The search index (52 KB gzipped) loads only when search is opened.

Security

  • Content-Security-Policy (production builds only). No inline scripts or event handlers remain in templates, and check_blogs.rb fails if one is added.
  • jQuery, Bootstrap, Popper and the Font Awesome CDN removed: four fewer third-party script origins.
  • Google Analytics loads only in production builds.
  • SECURITY.md, /.well-known/security.txt, robots.txt and a sitemap.

Build and deploy

  • Jekyll 4.4.1 with all gems updated.
  • .github/workflows/pages.yml builds every PR and deploys master with actions/deploy-pages (no stored token). Actions are pinned to commit SHAs, permissions are least-privilege, and checkout doesn't keep credentials.
  • Dependabot for gems and actions, waiting 7 days before proposing a new release.
  • Removed .travis.yml and deploy.sh, which pushed using a personal access token.

How to review locally

bundle config set --local path vendor/bundle
bundle install
bundle exec jekyll serve                         # http://localhost:4000
bundle exec ruby scripts/check_blogs.rb
JEKYLL_ENV=production bundle exec jekyll build   # with CSP and analytics, as deployed

Testing

  • check_blogs.rb passes. Its new checks were tested by breaking each one on purpose.
  • Checked in Chrome at desktop and 375px widths, in light and dark: homepage, posts, search (including the / shortcut), mobile menu, archives, author pages, 404 and Giscus.
  • Confirmed the CSP blocks inline scripts and unknown frames, and still allows YouTube, Ente, Airtable and Giscus.
  • Tested the theme button in headless Chromium:
    • switching both ways on light and dark systems
    • the saved choice and other open tabs
    • keyboard use, print and no-JavaScript
    • Giscus following the theme
  • Not yet verified: the workflow on GitHub (this PR is its first run) and Dependabot's cooldown setting.

Known effects

  • Old Twitter widget and Speaker Deck scripts inside a few posts are blocked by the CSP. Their quoted text and links still show.
  • Conflicts with Clarify company job submissions and volunteer introductions #109 on jobposting.md. When resolving, drop the static.airtable.com script: the CSP blocks it, and the form iframe works without it at a fixed height.
  • Cover images have an empty alt until a post sets the new optional image_alt front matter.

🤖 Generated with Claude Code

indiVar0508 and others added 2 commits November 9, 2026 23:23
Rebuild the theme around the BangPypers brand and drop the legacy
Mediumish/Bootstrap stack.

Design and UX
- New header, footer and homepage: upcoming meetups first, recent
  write-ups, community posts and ways to take part
- Official logo marks from bangpypers/assets, navy and yellow palette,
  Anek Latin and Source Serif 4 type
- Light and dark themes: follows the system setting, with a header
  button that remembers the reader's choice
- Accessible markup: skip link, landmarks, one h1 per page, single-link
  cards, visible focus, reduced motion respected
- Post pages with reading time, author cards, tags and share links;
  blog and archives grouped by year; proper 404 page
- Search in a native dialog, loaded only when opened

Security
- Content-Security-Policy in production builds; no inline scripts or
  event handlers anywhere in the templates
- Fix DOM XSS in search results (rendered with textContent)
- Remove jQuery, Bootstrap, Popper and Font Awesome CDNs
- Google Analytics only in production builds
- SECURITY.md, .well-known/security.txt, robots.txt and sitemap

Build and deploy
- Jekyll 4.4 with all gems updated
- Deploy with GitHub Actions instead of the classic Pages builder, so
  jekyll-archives runs and tag/year pages stop returning 404
- Fix jekyll-archives keys (year/month) that never generated pages
- SHA-pinned actions, least-privilege permissions, Dependabot with a
  7-day cooldown; remove Travis and the token-based deploy script
- check_blogs.rb also guards the CSP, inline scripts, search index,
  structured data, security.txt expiry and theme script loading

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The per-field replace in structuredata.html was a no-op, so a post title,
description or author name containing "</script>" could end the JSON-LD
script element early and inject HTML. Escape "<" once over the rendered
block instead, which also covers author names and site fields, and add a
check_blogs.rb test that renders the include with hostile values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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