diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 950bc21d..a5c8ff75 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -710,6 +710,41 @@ jobs: - name: Run website script tests run: node website/test_toEmbedUrl.mjs + # ── Website end-to-end + accessibility (Playwright + axe) ───────────────── + website-e2e: + name: Website (Playwright + axe) + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + + - name: Set up Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: "22" + cache: npm + cache-dependency-path: website/package-lock.json + + - name: Install dependencies + working-directory: website + run: npm ci + + - name: Install Playwright's Chromium + working-directory: website + run: npx playwright install --with-deps chromium + + - name: Run rendering, navigation, editor-removal, XSS, and accessibility tests + working-directory: website + run: npx playwright test + + - name: Upload Playwright report on failure + if: failure() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: website-playwright-report + path: website/playwright-report/ + retention-days: 7 + # ── Enforce branch flow: main may only receive PRs from dev ─────────────── # No-op on dev PRs (step skipped -> job succeeds). To allow hotfixes straight # to main, widen the condition below to also accept a 'hotfix/*' head branch. @@ -734,7 +769,7 @@ jobs: name: CI Summary runs-on: ubuntu-latest needs: - [lint, rule-validation, secret-scan, sast-bandit, sast-semgrep, sca-pip-audit, sbom, container-scan, backend-tests, frontend, website, enforce-source-branch] + [lint, rule-validation, secret-scan, sast-bandit, sast-semgrep, sca-pip-audit, sbom, container-scan, backend-tests, frontend, website, website-e2e, enforce-source-branch] if: always() steps: - name: Build summary @@ -750,6 +785,7 @@ jobs: BACKEND_TESTS: ${{ needs.backend-tests.result }} FRONTEND: ${{ needs.frontend.result }} WEBSITE: ${{ needs.website.result }} + WEBSITE_E2E: ${{ needs.website-e2e.result }} ENFORCE_SOURCE: ${{ needs.enforce-source-branch.result }} run: | python3 - <<'PYEOF' @@ -767,6 +803,7 @@ jobs: ("Backend Tests (pytest + coverage)", os.environ["BACKEND_TESTS"]), ("Frontend (lint + build)", os.environ["FRONTEND"]), ("Website (script tests)", os.environ["WEBSITE"]), + ("Website (Playwright + axe)", os.environ["WEBSITE_E2E"]), ("Enforce dev to main source", os.environ["ENFORCE_SOURCE"]), ] @@ -819,5 +856,6 @@ jobs: needs.backend-tests.result != 'success' || needs.frontend.result != 'success' || needs.website.result != 'success' || + needs.website-e2e.result != 'success' || needs.enforce-source-branch.result != 'success' run: exit 1 diff --git a/website/.gitignore b/website/.gitignore index e985853e..0912d6b5 100644 --- a/website/.gitignore +++ b/website/.gitignore @@ -1 +1,5 @@ .vercel +node_modules +test-results +playwright-report +.last-run.json diff --git a/website/README.md b/website/README.md index 228f9712..ab86ff65 100644 --- a/website/README.md +++ b/website/README.md @@ -23,7 +23,7 @@ Vercel picks up `vercel.json` automatically. Every push to `main` triggers a red ## Adding Content -All content lives in `website/content.js`. Edit it directly on a branch and open a PR to `dev`. Alternatively, use the built-in editor at the Blog Editor section (requires a GitHub personal access token with `repo` scope). +All content lives in `website/content.js`. Edit it directly on a branch and open a PR to `dev`. The built-in editor at the Blog Editor section can build and format the entry for you, but it no longer publishes for you directly — it does not ask for or use a GitHub token. Use "Export Entry" to get the formatted snippet, paste it into the right array in `website/content.js`, and open the PR yourself (see #297 — a page that can request a `repo`-scoped credential in the browser is a real risk on its own). ### Blog post @@ -47,7 +47,7 @@ All content lives in `website/content.js`. Edit it directly on a branch and open **Images in blog posts:** - Cover image: commit to `website/assets/blog/` and set `image: "assets/blog/filename.jpg"` - Inline images: use standard Markdown `![alt](assets/blog/filename.jpg)` inside the `content` field -- Max file size for GitHub API upload via the editor: **700 KB**. Larger files must be committed manually. +- The editor no longer uploads images for you — commit the file to `website/assets/blog/` yourself as part of your PR. **Video embeds:** - Paste a YouTube watch URL (`https://www.youtube.com/watch?v=...`) or Vimeo URL (`https://vimeo.com/...`) into the `video` field @@ -121,7 +121,7 @@ Paste the output as the `rules` array in `content.js`. | Section | Editor support | |---|---| -| Blog posts | Yes — Blog Post type (image upload, video embed, Markdown content) | +| Blog posts | Yes — Blog Post type (image preview, video embed, Markdown content) | | Events | Yes — Community Event type | | Contributors | Yes — New Contributor type | | Releases | Yes — Release type | @@ -145,4 +145,23 @@ python3 -m http.server 8080 --- +## Testing + +`node test_toEmbedUrl.mjs` runs the fast, pure-function tests (no browser needed). + +Rendering, navigation, the removed GitHub-token flow, an XSS regression corpus, and +accessibility (axe + keyboard) are covered by Playwright: + +```bash +cd website +npm install +npx playwright install --with-deps chromium # first run only +npm run test:e2e +``` + +The suite serves the site itself on `127.0.0.1:4173` (see `playwright.config.js`) — +no separate server needs to be running first. + +--- + Core philosophy: keep it technical, keep it open. diff --git a/website/index.html b/website/index.html index 552a5907..47b0a0f3 100644 --- a/website/index.html +++ b/website/index.html @@ -3,6 +3,22 @@ + OpenShield | Enterprise-Grade Open Source CSPM @@ -17,51 +33,18 @@ - + + + - +