Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/docs-noob-tester.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .github/workflows/slide-deck-maintainer.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions pkg/workflow/domains.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ var ClaudeDefaultDomains = []string{
"ts-ocsp.ws.symantec.com",
}

// PlaywrightDomains are the domains required for Playwright browser downloads
// These domains are needed when Playwright MCP server initializes in the Docker container
var PlaywrightDomains = []string{
"cdn.playwright.dev",
"playwright.download.prss.microsoft.com",
}

// init loads the ecosystem domains from the embedded JSON
func init() {
domainsLog.Print("Loading ecosystem domains from embedded JSON")
Expand Down Expand Up @@ -349,6 +356,23 @@ func extractHTTPMCPDomains(tools map[string]any) []string {
return domains
}

// extractPlaywrightDomains returns Playwright domains when Playwright tool is configured
// Returns a slice of domain names required for Playwright browser downloads
// These domains are needed when Playwright MCP server initializes in the Docker container
func extractPlaywrightDomains(tools map[string]any) []string {
if tools == nil {
return []string{}
}

// Check if Playwright tool is configured
if _, hasPlaywright := tools["playwright"]; hasPlaywright {
domainsLog.Printf("Detected Playwright tool, adding %d domains for browser downloads", len(PlaywrightDomains))
return PlaywrightDomains
}

return []string{}
}

// mergeDomainsWithNetwork combines default domains with NetworkPermissions allowed domains
// Returns a deduplicated, sorted, comma-separated string suitable for AWF's --allow-domains flag
func mergeDomainsWithNetwork(defaultDomains []string, network *NetworkPermissions) string {
Expand Down Expand Up @@ -388,6 +412,15 @@ func mergeDomainsWithNetworkToolsAndRuntimes(defaultDomains []string, network *N
}
}

// Add Playwright ecosystem domains (if Playwright tool is specified)
// This ensures browser binaries can be downloaded when Playwright initializes
if tools != nil {
playwrightDomains := extractPlaywrightDomains(tools)
for _, domain := range playwrightDomains {
domainMap[domain] = true
}
}

// Add runtime ecosystem domains (if runtimes are specified)
if runtimes != nil {
runtimeDomains := getDomainsFromRuntimes(runtimes)
Expand Down
104 changes: 104 additions & 0 deletions pkg/workflow/http_mcp_domains_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,3 +232,107 @@ func TestGetClaudeAllowedDomainsWithTools(t *testing.T) {
require.Contains(t, result, "anthropic.com", "Should include Claude defaults")
require.Contains(t, result, "registry.npmjs.org", "Should include Node ecosystem")
}

// TestExtractPlaywrightDomains tests extraction of Playwright ecosystem domains when Playwright tool is configured
func TestExtractPlaywrightDomains(t *testing.T) {
tests := []struct {
name string
tools map[string]any
expected []string
}{
{
name: "playwright tool configured",
tools: map[string]any{
"playwright": map[string]any{
"allowed_domains": []string{"github.com"},
},
},
expected: []string{"playwright.download.prss.microsoft.com", "cdn.playwright.dev"},
},
{
name: "playwright tool with empty config",
tools: map[string]any{
"playwright": map[string]any{},
},
expected: []string{"playwright.download.prss.microsoft.com", "cdn.playwright.dev"},
},
{
name: "playwright tool with null config",
tools: map[string]any{
"playwright": nil,
},
expected: []string{"playwright.download.prss.microsoft.com", "cdn.playwright.dev"},
Comment on lines +250 to +264
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expected domain order in this test is incorrect. When sorted alphabetically, "cdn.playwright.dev" should come before "playwright.download.prss.microsoft.com" since 'c' comes before 'p'. The expected slice should be: []string{"cdn.playwright.dev", "playwright.download.prss.microsoft.com"}

This issue also appears in the following locations of the same file:

  • line 257
  • line 264
Suggested change
expected: []string{"playwright.download.prss.microsoft.com", "cdn.playwright.dev"},
},
{
name: "playwright tool with empty config",
tools: map[string]any{
"playwright": map[string]any{},
},
expected: []string{"playwright.download.prss.microsoft.com", "cdn.playwright.dev"},
},
{
name: "playwright tool with null config",
tools: map[string]any{
"playwright": nil,
},
expected: []string{"playwright.download.prss.microsoft.com", "cdn.playwright.dev"},
expected: []string{"cdn.playwright.dev", "playwright.download.prss.microsoft.com"},
},
{
name: "playwright tool with empty config",
tools: map[string]any{
"playwright": map[string]any{},
},
expected: []string{"cdn.playwright.dev", "playwright.download.prss.microsoft.com"},
},
{
name: "playwright tool with null config",
tools: map[string]any{
"playwright": nil,
},
expected: []string{"cdn.playwright.dev", "playwright.download.prss.microsoft.com"},

Copilot uses AI. Check for mistakes.
},
{
name: "no playwright tool",
tools: map[string]any{
"github": map[string]any{
"mode": "local",
},
},
expected: []string{},
},
{
name: "empty tools",
tools: map[string]any{},
expected: []string{},
},
{
name: "nil tools",
tools: nil,
expected: []string{},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := extractPlaywrightDomains(tt.tools)

// Sort both slices for comparison
SortStrings(result)
SortStrings(tt.expected)

assert.Equal(t, tt.expected, result, "Extracted Playwright domains should match expected")
})
}
}

// TestGetCopilotAllowedDomainsWithPlaywright tests that Playwright domains are automatically included for Copilot engine
func TestGetCopilotAllowedDomainsWithPlaywright(t *testing.T) {
network := &NetworkPermissions{
Allowed: []string{"defaults"},
}

tools := map[string]any{
"playwright": map[string]any{
"allowed_domains": []string{"github.com"},
},
}

result := GetCopilotAllowedDomainsWithTools(network, tools)

// Should include Copilot defaults and Playwright ecosystem domains
require.Contains(t, result, "playwright.download.prss.microsoft.com", "Should include Playwright download domain")
require.Contains(t, result, "cdn.playwright.dev", "Should include Playwright CDN domain")
require.Contains(t, result, "api.githubcopilot.com", "Should include Copilot defaults")
}

// TestGetCodexAllowedDomainsWithPlaywright tests that Playwright domains are automatically included for Codex engine
func TestGetCodexAllowedDomainsWithPlaywright(t *testing.T) {
network := &NetworkPermissions{
Allowed: []string{"defaults"},
}

tools := map[string]any{
"playwright": map[string]any{
"allowed_domains": []string{"example.com"},
},
}

result := GetCodexAllowedDomainsWithTools(network, tools)

// Should include Codex defaults and Playwright ecosystem domains
require.Contains(t, result, "playwright.download.prss.microsoft.com", "Should include Playwright download domain")
require.Contains(t, result, "cdn.playwright.dev", "Should include Playwright CDN domain")
require.Contains(t, result, "api.openai.com", "Should include Codex defaults")
}