From d731dab5c968ec7098670fa1b523a715988c8db1 Mon Sep 17 00:00:00 2001 From: Michal Ferber Date: Thu, 30 Jul 2026 08:12:47 -0400 Subject: [PATCH] Parity wave 2: DS v2.10.1 Class C compliance; highlight.js inlined MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - highlight.js 11.9.0 + both GitHub themes inlined per §2 (no runtime CDNs) — the loader collapses to the global, call sites unchanged, theme toggling still flips the same element ids. Headless-verified: highlighting works, zero console errors. Page remains a single file. - §1 footer credit added, exact, with a runtime year (no-build page). - README: Class C stated in the opening paragraph, Credits table (highlight.js, BSD-3-Clause), link-back stamped v2.10.1. - .gitignore (§10); twitter:creator meta (§1); hardened one-job ci (§15: permissions: {}, SHA pin) running the §2 no-eval gate and the §1 mailto scan; dependabot github-actions entry. Owner calls left open (flagged, not decided): §9 privacy/terms note for Class C pages, and JetBrains Mono headings vs the page's current face. Co-Authored-By: Claude Fable 5 --- .github/dependabot.yml | 30 + .github/workflows/ci.yml | 26 + .gitignore | 10 + README.md | 12 +- index.html | 1266 +++++++++++++++++++++++++++++++++++++- scripts/no-eval.sh | 38 ++ 6 files changed, 1359 insertions(+), 23 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100755 scripts/no-eval.sh diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..34cf737 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,30 @@ +# TGWAB dependency updates — DEV-STANDARDS §15. +# +# Place at: .github/dependabot.yml +# +# Grouping caps a normal week at ~3 PRs instead of one per package — ungrouped +# Dependabot is how automated updates get muted and then ignored. +# +# DO NOT use this for a pnpm-11 repo's npm dependencies (wizard-web). Dependabot +# supports pnpm v7–v10 and cannot parse a pnpm 11 multi-document lockfile, so it +# opens zero PRs while appearing configured. Use templates/renovate.json there — +# this file's github-actions entry is still fine to keep alongside it. +# +# Class C Jekyll repos add a third entry with package-ecosystem: bundler. + +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + day: monday + time: "06:00" + timezone: America/New_York + open-pull-requests-limit: 2 + labels: [dependencies] + commit-message: + prefix: "chore(actions)" + groups: + actions: + patterns: ["*"] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..cf25f4f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,26 @@ +# §15 gates for a no-build single-file page. Deploy is GitHub Pages from main. +name: ci +on: + pull_request: + push: + branches: [main] +permissions: {} +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} +jobs: + ci: + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: + contents: read + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + # §2 gate: the page (with inlined highlight.js) must be eval-free. + - run: ./scripts/no-eval.sh . + # §1 gate: no mailto: anywhere in the page. + - run: | + set -euo pipefail + if grep -n 'mailto:' index.html; then echo "::error::mailto: in page (§1)"; exit 1; fi diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9223feb --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# OS / editor cruft (§10) +.DS_Store +Thumbs.db +*.swp +.idea/ +.vscode/ + +# Secrets never land in a repo (§10, §16) +.dev.vars* +.env* diff --git a/README.md b/README.md index b74c1db..9c82a43 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # GitHub Tree Browser -A single-file, client-only explorer for browsing any **public GitHub repository** as a collapsible tree on **GitHub Pages**. Previews images inline, renders text & code files with syntax highlighting, and gives one-click **raw**, **CDN**, and **GitHub** links. +A single-file, client-only explorer for browsing any **public GitHub repository** as a collapsible tree on **GitHub Pages**. **Class C micro-project** (§10): public, MIT, no custom domain. Previews images inline, renders text & code files with syntax highlighting, and gives one-click **raw**, **CDN**, and **GitHub** links. 🔗 **Live:** [michalaferber.github.io/github-tree-browser](https://michalaferber.github.io/github-tree-browser/) @@ -74,3 +74,13 @@ With a fine-grained PAT (no scopes needed for public repos, just `public_repo` i ## License MIT — see [LICENSE](LICENSE). + +## Credits + +| Component | Version | License | +| --- | --- | --- | +| [highlight.js](https://highlightjs.org) (inlined) | 11.9.0 | BSD-3-Clause | + +## Standards + +Built to the TGWAB Dev Standards **v2.10.1** (internal). diff --git a/index.html b/index.html index c08391c..c8ed0d4 100644 --- a/index.html +++ b/index.html @@ -17,6 +17,7 @@ + @@ -893,6 +894,1244 @@

GitHub Tree BrowserBrowse, preview, and copy raw URLs from any public + + + + + diff --git a/scripts/no-eval.sh b/scripts/no-eval.sh new file mode 100755 index 0000000..94bdf4f --- /dev/null +++ b/scripts/no-eval.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# TGWAB eval gate — DEV-STANDARDS §2. +# +# Place at: scripts/no-eval.sh · CI: ./scripts/no-eval.sh dist +# +# The §12 CSP never carries 'unsafe-eval', which blocks eval(), new Function(), +# bare Function("…"), and string-form setTimeout/setInterval/setImmediate. Anything +# this finds is code that will throw at runtime for a real user. +# +# Runs against BUILT output, not source: esbuild preserves the `eval` identifier +# through minification, so the check survives bundling. +# +# Escape hatch (§2): a vendor file that genuinely cannot be made eval-free goes in +# .eval-allowlist as a path prefix with a one-line reason, AND as a README deviation. +# The CSP MUST NOT be loosened instead. +set -euo pipefail + +TARGET="${1:-dist}" +ALLOW=".eval-allowlist" + +PATTERN='(^|[^A-Za-z0-9_$])eval[[:space:]]*\(|new[[:space:]]+Function[[:space:]]*\(|(^|[^A-Za-z0-9_$.])Function[[:space:]]*\([[:space:]]*["'"'"'`]|set(Timeout|Interval|Immediate)[[:space:]]*\([[:space:]]*["'"'"'`]' + +hits="$(grep -nEr "$PATTERN" \ + --include='*.js' --include='*.mjs' --include='*.cjs' --include='*.html' \ + "$TARGET" || true)" + +if [ -s "$ALLOW" ]; then + hits="$(printf '%s\n' "$hits" \ + | grep -vFf <(grep -v '^[[:space:]]*#' "$ALLOW" | grep -v '^[[:space:]]*$') || true)" +fi + +if [ -n "$hits" ]; then + printf '::error::runtime code-generation found in %s (CSP has no %s)\n' "$TARGET" "'unsafe-eval'" + printf '%s\n' "$hits" + exit 1 +fi + +printf 'eval-free: OK (%s)\n' "$TARGET"