How to Set Up Playwright Browser Automation with Domain Allow‑Listing in gh‑aw
To set up Playwright browser automation with domain allow‑listing in gh‑aw, declare an allowed_domains array in the workflow front‑matter under the playwright tool configuration; the MCP server will enforce this list at runtime, blocking all outbound traffic to non‑listed domains.
The gh‑aw extension embeds Playwright‑based browser automation directly into agentic workflows on GitHub Actions. To prevent unauthorized outbound network calls, gh‑aw implements a strict security model that requires an explicit allow‑list of domains the Playwright container may contact. This guide explains how to configure, compile, and verify domain allow‑listing using the actual source implementation.
Architecture of Domain Allow‑Listing in gh‑aw
Core Components
The allow‑list mechanism spans the parser, compiler, and runtime layers:
| Component | Responsibility | Key Source |
|---|---|---|
Tool definition – PlaywrightToolConfig |
Holds Playwright‑specific configuration, including allowed_domains. |
[pkg/workflow/tools_types.go](https://github.com/github/gh-aw/blob/main/pkg/workflow/tools_types.go#L275-L290) |
MCP Playwright config extractor – PlaywrightDockerArgs & AllowedDomains |
Reads the allowed_domains entry from the front‑matter and converts it into a slice of strings that the MCP server will enforce. |
[pkg/workflow/mcp_playwright_config.go](https://github.com/github/gh-aw/blob/main/pkg/workflow/mcp_playwright_config.go#L11) |
MCP parser – ParseMCP |
During front‑matter parsing, detects the allowed_domains key, resolves any GitHub Actions expressions, and stores the result in the tool config. |
[pkg/parser/mcp.go](https://github.com/github/gh-aw/blob/main/pkg/parser/mcp.go#L455-L456) |
YAML compiler – compiler_yaml.go |
When the final workflow YAML is generated, the allow‑list is rendered as a JSON array under the playwright MCP tool configuration. |
[pkg/workflow/compiler_yaml.go](https://github.com/github/gh-aw/blob/main/pkg/workflow/compiler_yaml.go#L507-L509) |
| Runtime enforcement – MCP server / firewall | The MCP sandbox validates outbound HTTP(S) requests against the configured allow‑list, blocking any domain that is not listed. This is reflected in log/guardrail reports (allowed_domains fields). |
[pkg/cli/logs_report.go](https://github.com/github/gh-aw/blob/main/pkg/cli/logs_report.go) |
Data Flow from Front‑Matter to Runtime
- User writes a workflow markdown file with a
tools:block that includes Playwright and anallowed_domainsarray. - The parser (
ParseMCPinpkg/parser/mcp.go) reads the array, handling plain strings or${{ secrets... }}expressions. - The MCP config extractor (
pkg/workflow/mcp_playwright_config.go) builds aPlaywrightDockerArgsstruct that stores the sanitized domain list. - The compiler (
pkg/workflow/compiler_yaml.go) inserts the list into the generated workflow YAML (allowed_domains: [...]). - At runtime, the MCP server only allows outbound traffic to those domains, providing a strong security boundary.
Declaring the Allow‑List in Workflow Front‑Matter
Add a tools block to the top of your workflow markdown file:
---
engine: copilot # or claude, codex, custom
tools:
playwright:
version: "v1.41.0" # optional – overrides default version
allowed_domains:
- "example.com"
- "api.github.com"
- "${{ secrets.ALLOWED_DOMAIN }}" # can be a secret expression
---
Each entry may be a plain domain string, a wildcard pattern (*.github.com), or a GitHub Actions expression that resolves to a domain at runtime. If the array is omitted, gh‑aw defaults to localhost, effectively disabling external network access.
The parser validates the array in pkg/workflow/mcp_config_validation.go, throwing an error if the format is invalid.
Compiling and Running the Workflow
Compile the markdown into a GitHub Actions workflow:
gh aw compile path/to/your-workflow.md
The compiled .github/workflows/*.yml will contain a section similar to:
steps:
- name: Playwright MCP
uses: github/[email protected]
with:
tools: |
playwright:
allowed_domains: ["example.com","api.github.com"]
Execute the workflow via the standard GitHub Actions run, or invoke gh aw run for a local test:
gh aw run path/to/your-workflow.md
Inspect the MCP logs to verify the allow‑list was applied:
gh aw mcp logs --workflow your-workflow
The JSON log output includes an allowed_domains field (see pkg/cli/logs_report.go), confirming which domains were permitted during execution.
Practical Examples
Minimal Workflow with Static Domains
Create test-playwright-allowlist.md:
---
engine: copilot
tools:
playwright:
allowed_domains:
- "example.com"
- "api.github.com"
---
# A simple Playwright script that navigates to example.com
{{/* language=javascript */}}
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
console.log(await page.title());
await browser.close();
})();
This compiles to a workflow that only permits outbound calls to example.com and api.github.com.
Dynamic Domains via GitHub Secrets
---
engine: copilot
tools:
playwright:
allowed_domains:
- "${{ secrets.ALLOWED_API_DOMAIN }}"
---
# Playwright script that will hit whatever domain is stored in the secret
The parser resolves the expression during workflow execution, and the MCP server enforces the resolved value at runtime.
Testing with the CLI
The repository ships a ready‑made test workflow: pkg/cli/workflows/test-playwright-args.md. It demonstrates argument passing and the allow‑list in action. Run it locally:
gh aw run pkg/cli/workflows/test-playwright-args.md
Summary
- gh‑aw embeds Playwright automation into agentic workflows but requires an explicit
allowed_domainsarray for security. - The allow‑list is declared in workflow front‑matter under
tools.playwright.allowed_domainsand supports plain strings, wildcards, and GitHub Actions expressions. - Key source files handling the flow include
pkg/workflow/tools_types.go(struct definition),pkg/workflow/mcp_playwright_config.go(extraction),pkg/parser/mcp.go(parsing), andpkg/workflow/compiler_yaml.go(YAML generation). - Runtime enforcement occurs in the MCP server sandbox, which blocks any outbound request to domains not in the list.
- Verify configuration using
gh aw mcp logs --workflow <name>to inspect theallowed_domainsfield in execution logs.
Frequently Asked Questions
What happens if I omit the allowed_domains array?
If you omit the allowed_domains array, gh‑aw defaults to localhost, effectively disabling external network access for the Playwright container. This prevents any outbound HTTP(S) requests to external APIs or websites, ensuring a secure-by-default posture.
Can I use wildcards in domain allow‑listing?
Yes, you can use wildcard patterns such as *.github.com in the allowed_domains array. The MCP server interprets these patterns when validating outbound requests, allowing subdomains that match the specified wildcard while still blocking unrelated domains.
How are secrets resolved in the allowed_domains list?
GitHub Actions expressions like ${{ secrets.ALLOWED_DOMAIN }} are resolved by the parser in pkg/parser/mcp.go during the workflow compilation phase. The resolved string value is then passed through pkg/workflow/mcp_playwright_config.go and rendered into the final YAML, where the MCP server receives the literal domain name at runtime.
Where can I verify that the allow‑list was applied?
You can verify the active allow‑list by inspecting the MCP execution logs using the command gh aw mcp logs --workflow <your-workflow-name>. The JSON output includes an allowed_domains field (as defined in pkg/cli/logs_report.go) that lists every domain permitted during that specific run.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →