Repository navigation
prose_checks: stop flagging "rather than" / "would rather" as weasel words #307
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |