name: Live Site Browser Audit on: push: branches: [main] workflow_dispatch: permissions: contents: read actions: read concurrency: group: live-browser-audit-main cancel-in-progress: true jobs: audit-live-site: name: audit-live-site (${{ matrix.label }}) strategy: fail-fast: false matrix: include: - label: core-navigation routes: '/,/systems-administration.html,/projects.html,/proof.html,/dashboard.html,/resume.html,/contact.html' - label: primary-projects routes: '/windows-laps-gpo.html,/entra-cloud-sync.html,/m365-messaging-security.html,/windows-autopilot-intune.html,/macos-abm-intune-runbook.html,/m365-graph-administration-lab.html,/on-prem-home-lab.html,/windows-admin-center-lab.html' - label: supporting-projects routes: '/home-lab-operations-proof.html,/active-directory-lab.html,/network-segmentation.html,/macvm01.html,/infrastructure.html,/app01-storage-expansion.html,/servicenow-request-fulfillment.html' - label: evidence-hubs routes: '/evidence-library/,/evidence/,/evidence/claim-map.html,/home-lab/,/home-lab/evidence-catalog.html,/microsoft-365/,/microsoft-365/evidence-catalog.html' - label: skills-and-project-evidence routes: '/systems-skills/,/systems-skills/evidence-map.html,/evidence-library/projects/on-prem-home-lab/scvmm-2022/,/evidence-library/projects/on-prem-home-lab/azure-arc-hybrid-management/,/projects/windows-laps-gpo/evidence/,/projects/windows-autopilot-intune/evidence/,/projects/macos-abm-intune-runbook/evidence/' runs-on: ubuntu-latest timeout-minutes: 60 steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.12' - name: Wait for matching GitHub Pages deployment env: GH_TOKEN: ${{ github.token }} REPO: ${{ github.repository }} SHA: ${{ github.sha }} shell: bash run: | set -euo pipefail echo "Waiting for Pages deployment for $SHA" for attempt in $(seq 1 90); do payload="$(curl -fsSL \ -H "Authorization: Bearer $GH_TOKEN" \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ "https://api.github.com/repos/$REPO/actions/runs?head_sha=$SHA&per_page=100")" result="$(printf '%s' "$payload" | jq -r '[.workflow_runs[] | select(.name == "pages build and deployment")][0] | if . == null then "missing" else (.status + ":" + (.conclusion // "")) end')" echo "Attempt $attempt: $result" if [[ "$result" == "completed:success" ]]; then exit 0 fi if [[ "$result" == completed:* && "$result" != "completed:success" ]]; then echo "Matching Pages deployment failed: $result" >&2 exit 1 fi sleep 10 done echo "Timed out waiting for the matching Pages deployment." >&2 exit 1 - name: Install Playwright run: | python -m pip install --disable-pip-version-check playwright==1.55.0 python -m playwright install chromium - name: Configure production Chromium profile shell: bash run: | python - <<'PY' from pathlib import Path path = Path('scripts/audits/live-browser-audit.py') text = path.read_text(encoding='utf-8') old_context = 'context = await browser.new_context(viewport={"width": VIEWPORT_WIDTH, "height": 1000}, locale="en-US", timezone_id="America/Chicago")' new_context = '''context = await browser.new_context( viewport={"width": VIEWPORT_WIDTH, "height": 1000}, locale="en-US", timezone_id="America/Chicago", user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36", extra_http_headers={ "Accept-Language": "en-US,en;q=0.9", "Upgrade-Insecure-Requests": "1", }, )''' old_pause = 'await page.wait_for_timeout(150)' new_pause = 'await page.wait_for_timeout(500)' if old_context not in text: raise SystemExit('Expected browser context line was not found; refusing to patch an unknown audit version.') if old_pause not in text: raise SystemExit('Expected navigation settling delay was not found; refusing to patch an unknown audit version.') text = text.replace(old_context, new_context, 1).replace(old_pause, new_pause, 1) path.write_text(text, encoding='utf-8') PY - name: Run live Chromium click audit env: PORTFOLIO_BASE_URL: https://jeremyfontenot.online PORTFOLIO_BROWSER_AUDIT_MAX_PAGES: '100' PORTFOLIO_BROWSER_AUDIT_WORKERS: '1' PORTFOLIO_BROWSER_NAV_TIMEOUT_MS: '25000' PORTFOLIO_BROWSER_AUDIT_ROUTES: '${{ matrix.routes }}' PORTFOLIO_BROWSER_AUDIT_ROUTE_DELAY_MS: '0' run: python scripts/audits/live-browser-audit.py - name: Upload live browser audit report if: always() uses: actions/upload-artifact@v4 with: name: live-browser-audit-${{ matrix.label }}-${{ github.sha }} path: artifacts/live-browser-audit.json if-no-files-found: warn audit-live-sitemap: name: audit-live-sitemap runs-on: ubuntu-latest timeout-minutes: 15 steps: - name: Wait for matching GitHub Pages deployment env: GH_TOKEN: ${{ github.token }} REPO: ${{ github.repository }} SHA: ${{ github.sha }} shell: bash run: | set -euo pipefail echo "Waiting for Pages deployment for $SHA" for attempt in $(seq 1 90); do payload="$(curl -fsSL \ -H "Authorization: Bearer $GH_TOKEN" \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ "https://api.github.com/repos/$REPO/actions/runs?head_sha=$SHA&per_page=100")" result="$(printf '%s' "$payload" | jq -r '[.workflow_runs[] | select(.name == "pages build and deployment")][0] | if . == null then "missing" else (.status + ":" + (.conclusion // "")) end')" echo "Attempt $attempt: $result" if [[ "$result" == "completed:success" ]]; then exit 0 fi if [[ "$result" == completed:* && "$result" != "completed:success" ]]; then echo "Matching Pages deployment failed: $result" >&2 exit 1 fi sleep 10 done echo "Timed out waiting for the matching Pages deployment." >&2 exit 1 - name: Validate production sitemap shell: bash run: | set -euo pipefail headers="$(mktemp)" body="$(mktemp)" status="$(curl -sS -D "$headers" -o "$body" -w '%{http_code}' \ -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/152.0.0.0 Safari/537.36' \ -H 'Accept: application/xml,text/xml;q=0.9,*/*;q=0.8' \ https://jeremyfontenot.online/sitemap.xml)" echo "sitemap.xml HTTP $status" cat "$headers" if [[ "$status" != "200" ]]; then echo "Production sitemap did not return HTTP 200." >&2 head -c 2000 "$body" >&2 || true exit 1 fi grep -q '&2 exit 1 fi grep -q 'https://jeremyfontenot.online/evidence-library/projects/on-prem-home-lab/scvmm-2022/' "$body" grep -q 'https://jeremyfontenot.online/evidence-library/projects/on-prem-home-lab/azure-arc-hybrid-management/' "$body" echo "Production sitemap validation SUCCESS: $count canonical discovery URLs."