Playwright read-only policy (v1)

Applies to: forge_lcdl.playwright (planned) and any host wiring that calls it. Version: v1 read-only guarantee — stricter than “read-mostly”; writes and secret export are out of scope.

Updated

Trust model

Actor Responsibility
User Completes login/MFA in the browser; approves domains and downloads per org policy.
Playwright / host Maintains the authorized session; exposes a narrow attach API to LCDL.
forge-lcdl Reads through the session facade only; normalizes to UnifiedItem; never escalates to private APIs or stolen credentials.
Consumer app Retention, audit, and human approval for any action beyond read.

LCDL does not ask for passwords, bypass MFA, or export harvested browser tokens. Read-only HTTP GET on allowlisted hosts (graph.microsoft.com, *.sharepoint.com, tenant OWA hosts) using the attached Playwright browser session (same pattern as SharePoint library REST) is permitted for list/count harvest only — no POST/PATCH/DELETE and no separate app registration inside LCDL.

Allowed operations (v1)

Category Examples
Session Attach to an existing authorized playwright session; query is_attached
Navigation Navigate to approved domains/URLs (allowlist per source)
Observation Read visible page title, metadata, and text exposed by the facade
Snapshots DOM / accessibility snapshots and derived text for normalization
Files Inspect or download bytes only when session policy permits read-only local extraction (no upload path)
Development Write local tests, docs, logs, and audit artifacts in the repo/CI

Disallowed operations (v1)

Category Examples (non-exhaustive)
Messaging / workflow writes Send, reply, forward, approve, reject, submit, complete, acknowledge
Content mutation Upload, delete, rename, move, share, permission changes
UI mutation Click submit/action controls, type into forms, fill forms, select options that commit state
Secret export Cookies, localStorage/sessionStorage, storage state files, auth headers, access/refresh tokens, hidden credential fields
Private APIs Workday REST or app-private APIs without an explicit policy carve-out
Non-session Graph Graph/SharePoint calls with application credentials exported from LCDL — forbidden
Bypass Credential prompts inside LCDL, MFA bypass, token replay from harvested material

If a host exposes tools beyond this policy, playwright.policy must deny them at the LCDL boundary even if the runtime could invoke them.

Alignment with MCP readmostly_playwright

The existing MCP preset McpPolicy.readmostly_playwright() is the reference ceiling for browser tool posture when playwright delegates to Playwright-like MCP tools:

Posture MCP preset Playwright v1
Navigate / snapshot / screenshot Allow Allow (via facade)
Click / type / fill / press key Approval required Deny (not merely approval)
Cookie/storage set/clear, set_storage_state, evaluate, file upload Deny Deny
Network route / unsafe run_code Deny Deny

Playwright v1 is stricter than “read-mostly”: mutation-capable tools are blocked in code, not left for operator approval inside LCDL.

Policy layers (implementation)

Entry API (e.g. read_outlook_inbox)
    → playwright.policy.assert_readonly_operation(op)
    → playwright.policy.validate_url(url, source_system)
    → playwright.policy.filter_tool_name(name)      # when MCP bridge used
    → PlaywrightSession.* (only read methods exposed on Protocol)
    → normalizer (no side effects)

Domain allowlists

Per-source presets (configured in playwright/policy.py, later step) constrain navigation, for example:

Source Typical host patterns (illustrative)
Outlook outlook.office.com, outlook.office365.com, tenant-specific OWAs
Teams teams.microsoft.com
SharePoint *.sharepoint.com
OneDrive onedrive.live.com, SharePoint-hosted OneDrive paths
Workday Customer Workday hostnames (explicit config required)

Exact lists are operator-configurable; defaults are conservative (deny unknown hosts).

Body and PII fields

body_text and rich previews are included in UnifiedItem only when:

  • the snapshot visibly contains the content, and
  • the caller’s policy flags allow full body (vs preview-only).

Tests use fixtures with synthetic text — never production mail bodies in the repo.

Data that may appear in artifacts

Field Allowed content Forbidden content
title, body_preview, body_text Visible UI text Hidden fields, token-like strings
url Page or item deep link URLs with embedded secrets
provenance Source id, normalizer version, snapshot id Cookie names, header dumps
raw_ref Stable non-secret locator (row index, aria ref) Session ids, bearer tokens
attachments Filename, size, mime, readonly download ref Raw file paths outside policy

Redaction rules mirror Data handling: file bugs with REDACTED tokens; do not commit live session captures.

File read policy

Rule Detail
Local only Downloaded bytes stay in memory or temp paths controlled by the host; LCDL does not persist mailbox content by default.
Formats PPTX, XLSX, DOCX, PDF — text/metadata extraction only; no macro execution.
Optional deps Parsers may live behind extras; missing deps → clear PlaywrightError, not silent network fetch.

Enforcement and review

Mechanism When
PlaywrightSession Protocol surface Only read methods on the typed API
policy.py URL, operation, and tool-name checks
Unit tests Denied ops return policy_denied; snapshots never contain Set-Cookie patterns in fixtures
Code review PDCA guardrails (.cursor/rules/lcdl-playwright-pdca.mdc)
Live tests Opt-in only; never in default CI

Narrow exceptions (v1)

Exception Scope
SharePoint / Graph GET page.context.request.get with session cookies on allowlisted hosts; list/metadata only
Read-state restore Allowlisted evaluate restore_row_unread only after allowlisted list_row click when preserve_unread=true on outlook_read_conversation_thread — not general mark-read/unread UI automation

Future work (explicitly out of v1)

  • Graph/REST with application credentials (client id/secret) — separate design and policy doc.
  • “Read-mostly” with human-approved clicks — not in v1; would require new policy tier and threat-model update.
  • Write-back tasks (send mail, approve Workday task) — forbidden until a major version and new contract family.

References