# Playwright Egress Guard Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [x]`) syntax for tracking.

**Goal:** Protect all local Playwright pages from non-loopback HTTP and WebSocket connections.

**Architecture:** Install HTTP and WebSocket routes on the existing `BrowserContext`. Block service workers through the shared Playwright configuration.

**Tech Stack:** Node.js, Playwright 1.62, Node test runner, Docker Compose

---

### Task 1: Add failing routing tests

**Files:**

- Modify: `tests/playwright/local-routing.spec.js`
- Modify: `tests/unit/url-policy.test.js`

- [x] **Step 1: Add WebSocket URL policy tests**

Add assertions that accept `ws://localhost`, `ws://127.0.0.1`, and `wss://[::1]`.
Add assertions that reject a non-WebSocket scheme and `ws://0.0.0.0`.

- [x] **Step 2: Add context routing tests**

Add one Playwright test for each path:

```javascript
test('local routing blocks a non-loopback image request', async ({ context, page }) => {});
test('local routing blocks a non-loopback popup request', async ({ context, page }) => {});
test('local routing blocks a non-loopback WebSocket request', async ({ context, page }) => {});
test('Playwright blocks service-worker registration before the script request', async ({ context, page }) => {});
```

Use local HTTP and WebSocket receivers.
Count each receiver request or connection.
Include the receiver hits in each assertion message.

- [x] **Step 3: Run the focused tests**

Run:

```bash
node --test tests/unit/url-policy.test.js
npx playwright test tests/playwright/local-routing.spec.js --reporter=line
```

Expected: The new tests fail because the current guard uses page-level HTTP routing.

### Task 2: Implement the context guard

**Files:**

- Modify: `tests/playwright/url-policy.js`
- Modify: `tests/playwright/local-request-routing.js`
- Modify: `tests/playwright/local-site.spec.js`
- Modify: `playwright.config.js`

- [x] **Step 1: Add WebSocket URL validation**

Add this public function:

```javascript
function validateLocalWebSocketUrl(value) {
  const url = new URL(value);
  if (url.protocol !== 'ws:' && url.protocol !== 'wss:') {
    throw new Error('WebSocket URL must use WS or WSS.');
  }
  validateLoopbackHost(url, 'WebSocket URL');
  return url;
}
```

- [x] **Step 2: Install context routes**

Change the helper to accept a `BrowserContext`.
Use `context.route('**/*', handler)` for HTTP.
Use `context.routeWebSocket('**/*', handler)` for WebSockets.
Call `connectToServer()` only for an approved WebSocket URL.
Close a forbidden WebSocket without a server connection.

- [x] **Step 3: Block service workers**

Add this option to `playwright.config.js`:

```javascript
serviceWorkers: 'block',
```

- [x] **Step 4: Update the local test**

Install the guard on `page.context()` before `page.goto()`.
Keep the blocked URL assertion and server-status assertion.

- [x] **Step 5: Run the focused tests**

Run:

```bash
node --test tests/unit/url-policy.test.js
npx playwright test tests/playwright/local-routing.spec.js --reporter=line
```

Expected: All focused tests pass.

### Task 3: Update setup instructions

**Files:**

- Modify: `README.md`

- [x] **Step 1: Add dependency setup commands**

Add these commands before local validation:

```bash
npm ci
npx playwright install chromium
```

- [x] **Step 2: Review the setup sequence**

Confirm that `npm ci` and the Chromium install occur before `npm test`.

### Task 4: Verify and commit

**Files:**

- Verify all modified files.

- [x] **Step 1: Run all offline checks**

Run:

```bash
npm test
npx playwright test tests/playwright/local-routing.spec.js --reporter=line
git diff --check
```

Expected: All commands pass.

- [x] **Step 2: Run the local stack check**

Run:

```bash
docker compose --env-file .env.example up -d --wait
npm run test:local
docker compose --env-file .env.example down --volumes
```

Expected: The local test passes.

- [x] **Step 3: Commit**

Run:

```bash
git add README.md playwright.config.js tests docs/superpowers/plans/2026-07-28-playwright-egress-guard.md
git commit -m "Guard Playwright browser contexts"
```

## Completion

All plan tasks are complete.
The final repository is `https://github.com/Eagle-Forum-Education-Legal/PS-Site-Rebuild`.
This plan remains as historical implementation documentation.
