Skip to content

prose_checks: stop flagging "rather than" / "would rather" as weasel words #307

prose_checks: stop flagging "rather than" / "would rather" as weasel words

prose_checks: stop flagging "rather than" / "would rather" as weasel words #307

Workflow file for this run

name: Deploy Pelican Site
on:
push:
branches: [main]
pull_request:
branches: [main]
concurrency:
group: pages-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || 'deploy' }}
cancel-in-progress: true
permissions:
contents: write
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Initialize submodules
run: git submodule update --init --depth=1
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.13"
cache: pip
- name: Install dependencies
# --no-deps because Pelican 4.12 hard-pins Pygments<2.20.0, but we
# override Pygments to 2.20.0 in requirements.txt to patch the
# AdlLexer ReDoS advisory (GHSA, dependabot alert #1). Every
# transitive dep is already pinned with hashes in requirements.txt,
# so --no-deps is safe and avoids the resolver conflict.
run: pip install --require-hashes --no-deps -r requirements.txt
- name: Refresh About page from GitHub profile README
run: scripts/fetch_about.sh
- name: Build site
run: pelican content -o output -s publishconf.py
- name: Build search index (Pagefind)
# Static same-origin search: writes the UI assets and chunked index to
# output/pagefind/, all fetched same-origin, so a strict script-src /
# connect-src 'self' CSP keeps working. Indexing is scoped by
# data-pagefind-body (articles + content pages only), which keeps the
# noindexed /drafts/ pages OUT of the search index. Version pinned;
# the runner's preinstalled Node is sufficient.
run: npx --yes pagefind@1.5.2 --site output
- name: Add CNAME file
run: echo rivassec.com > output/CNAME
- name: Add static tool to sitemap
# The IAM Blast Radius tool ships as a static file (STATIC_PATHS), so
# Pelican's sitemap plugin does not emit it. Inject its canonical URL
# after the build. Idempotent. The page is index,follow, so the
# canonical/noindex guard is satisfied.
run: |
python3 - <<'PY'
from pathlib import Path
p = Path('output/sitemap.xml')
s = p.read_text(encoding='utf-8')
url = '<url><loc>https://rivassec.com/tools/iam-blast-radius/</loc><changefreq>monthly</changefreq><priority>0.6</priority></url>'
if 'tools/iam-blast-radius' not in s and '</urlset>' in s:
p.write_text(s.replace('</urlset>', url + '\n</urlset>'), encoding='utf-8')
print('sitemap: tool URL injected')
else:
print('sitemap: tool URL already present or no </urlset>')
PY
- name: Enforce strict CSP preconditions (no inline styles/scripts)
# Keeps style-src 'self' / script-src 'self' safe: if a template
# change ever introduces an inline style="..." or <style> block
# or onclick= handler, this fails CI before deploy. See
# docs/security-headers.md for the CSP we ship.
run: |
python3 scripts/csp_audit.py output
- name: Check links in built site
# URL exclusions live in .lycheeignore (single source of truth, shared
# with the weekly link-rot workflow; lychee reads it automatically).
# Path exclusions stay inline: .lycheeignore holds URL patterns only.
uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0
with:
args: >-
--no-progress
--base https://rivassec.com
--remap "https://rivassec.com/ file://${{ github.workspace }}/output/"
--verbose
--accept 200..=299,429
--max-retries 5
--retry-wait-time 2
--exclude-path output/feeds
--exclude-path output/tools
'./output/**/*.html'
format: detailed
fail: true
- name: Deploy to GitHub Pages
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: |
ghp-import -n output -b gh-pages
git push origin gh-pages --force