Skip to content

Commit 56546ee

Browse files
authored
feat: Add network permissions support for Claude engine (#227)
* feat: Add network permissions support for Claude engine Signed-off-by: Jiaxiao Zhou <duibao55328@gmail.com> * fix: Update pull request trigger Signed-off-by: Jiaxiao Zhou <duibao55328@gmail.com> * fix: Update allowed domains for network permissions to docs.github.com Signed-off-by: Jiaxiao Zhou <duibao55328@gmail.com> * feat: Update network permissions to include WebFetch and WebSearch tools Signed-off-by: Jiaxiao Zhou <duibao55328@gmail.com> * enable debug Signed-off-by: Jiaxiao Zhou <duibao55328@gmail.com> * fix: Enforce domain restrictions for WebSearch tool and improve feedback on access blocks Signed-off-by: Jiaxiao Zhou <duibao55328@gmail.com> * feat: Add engine-specific validation for workflow frontmatter and network permissions Signed-off-by: Jiaxiao Zhou <duibao55328@gmail.com> * feat: Implement network permissions validation and deny-all policy for Claude engine Signed-off-by: Jiaxiao Zhou <duibao55328@gmail.com> * docs: Add engine network permissions for Claude engine with deny-by-default policy Signed-off-by: Jiaxiao Zhou <duibao55328@gmail.com> * docs: Clarify wildcard domain matching and permissions in frontmatter and security notes Signed-off-by: Jiaxiao Zhou <duibao55328@gmail.com> * regenerate the yaml Signed-off-by: Jiaxiao Zhou <duibao55328@gmail.com> * run linter Signed-off-by: Jiaxiao Zhou <duibao55328@gmail.com> * fix: Update time parsing to use local timezone and adjust future time test for execution buffer Signed-off-by: Jiaxiao Zhou <duibao55328@gmail.com> * fix: update the test case to use lowercase 'engine' Signed-off-by: Jiaxiao Zhou <duibao55328@gmail.com> --------- Signed-off-by: Jiaxiao Zhou <duibao55328@gmail.com>
1 parent 119259f commit 56546ee

27 files changed

Lines changed: 2131 additions & 91 deletions

.github/workflows/example-engine-network-permissions.lock.yml

Lines changed: 572 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
on:
3+
pull_request:
4+
branches:
5+
- main
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read
10+
11+
engine:
12+
id: claude
13+
permissions:
14+
network:
15+
allowed:
16+
- "docs.github.com"
17+
18+
tools:
19+
claude:
20+
allowed:
21+
WebFetch:
22+
WebSearch:
23+
---
24+
25+
# Secure Web Research Task
26+
27+
Please research the GitHub API documentation or Stack Overflow and find information about repository topics. Summarize them in a brief report.

.github/workflows/test-claude.lock.yml

Lines changed: 108 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.github/workflows/test-claude.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ on:
1111
engine:
1212
id: claude
1313
model: claude-3-5-sonnet-20241022
14+
permissions:
15+
network:
16+
allowed: []
1417
timeout_minutes: 10
1518
permissions:
1619
pull-requests: write

docs/frontmatter.md

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ The YAML frontmatter supports standard GitHub Actions properties plus additional
1818
- `steps`: Custom steps for the job
1919

2020
**Properties specific to GitHub Agentic Workflows:**
21-
- `engine`: AI engine configuration (claude/codex) with optional max-turns setting
21+
- `engine`: AI engine configuration (claude/codex) with optional max-turns setting and network permissions
2222
- `tools`: Available tools and MCP servers for the AI engine
2323
- `cache`: Cache configuration for workflow dependencies
2424
- `output`: [Safe Output Processing](safe-outputs.md) for automatic issue creation and comment posting.
@@ -161,13 +161,21 @@ engine:
161161
version: beta # Optional: version of the action
162162
model: claude-3-5-sonnet-20241022 # Optional: specific LLM model
163163
max-turns: 5 # Optional: maximum chat iterations per run
164+
permissions: # Optional: engine-level permissions (only Claude is supported)
165+
network: # Network access control
166+
allowed: # List of allowed domains
167+
- "api.example.com"
168+
- "*.trusted.com"
164169
```
165170

166171
**Fields:**
167172
- **`id`** (required): Engine identifier (`claude`, `codex`)
168173
- **`version`** (optional): Action version (`beta`, `stable`)
169174
- **`model`** (optional): Specific LLM model to use
170175
- **`max-turns`** (optional): Maximum number of chat iterations per run (cost-control option)
176+
- **`permissions`** (optional): Engine-level permissions
177+
- **`network`** (optional): Network access control
178+
- **`allowed`** (optional): List of allowed domains for WebFetch and WebSearch
171179

172180
**Model Defaults:**
173181
- **Claude**: Uses the default model from the claude-code-base-action (typically latest Claude model)
@@ -191,6 +199,88 @@ engine:
191199
3. Helps prevent runaway chat loops and control costs
192200
4. Only applies to engines that support turn limiting (currently Claude)
193201

202+
## Engine Network Permissions
203+
204+
> This is only supported by the claude engine today.
205+
206+
Control network access for AI engines using the `permissions` field in the `engine` block:
207+
208+
```yaml
209+
engine:
210+
id: claude
211+
permissions:
212+
network:
213+
allowed:
214+
- "api.example.com" # Exact domain match
215+
- "*.trusted.com" # Wildcard matches any subdomain (including nested subdomains)
216+
```
217+
218+
### Security Model
219+
220+
- **Deny by Default**: When network permissions are specified, only listed domains are accessible
221+
- **Engine vs Tools**: Engine permissions control the AI engine itself, separate from MCP tool permissions
222+
- **Hook Enforcement**: Uses Claude Code's hook system for runtime network access control
223+
- **Domain Validation**: Supports exact matches and wildcard patterns (`*` matches any characters including dots, allowing nested subdomains)
224+
225+
### Examples
226+
227+
```yaml
228+
# Allow specific APIs only
229+
engine:
230+
id: claude
231+
permissions:
232+
network:
233+
allowed:
234+
- "api.github.com"
235+
- "httpbin.org"
236+
237+
# Allow all subdomains of a trusted domain
238+
# Note: "*.github.com" matches api.github.com, subdomain.github.com, and even nested.api.github.com
239+
engine:
240+
id: claude
241+
permissions:
242+
network:
243+
allowed:
244+
- "*.company-internal.com"
245+
- "public-api.service.com"
246+
247+
# Deny all network access (empty list)
248+
engine:
249+
id: claude
250+
permissions:
251+
network:
252+
allowed: []
253+
```
254+
255+
### Permission Modes
256+
257+
1. **No network permissions**: Unrestricted access (backwards compatible)
258+
```yaml
259+
engine:
260+
id: claude
261+
# No permissions block - full network access
262+
```
263+
264+
2. **Empty allowed list**: Complete network access denial
265+
```yaml
266+
engine:
267+
id: claude
268+
permissions:
269+
network:
270+
allowed: [] # Deny all network access
271+
```
272+
273+
3. **Specific domains**: Granular access control to listed domains only
274+
```yaml
275+
engine:
276+
id: claude
277+
permissions:
278+
network:
279+
allowed:
280+
- "trusted-api.com"
281+
- "*.safe-domain.org"
282+
```
283+
194284
## Output Configuration (`output:`)
195285

196286
See [Safe Output Processing](safe-outputs.md) for automatic issue creation and comment posting.

docs/security-notes.md

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ In addition, the compilation step of Agentic Workflows enforces additional secur
4848
- **Expression restrictions** - only a limited set of expressions are allowed in the workflow frontmatter, preventing arbitrary code execution
4949
- **Highly restricted commands** - by default, no commands are allowed to be executed, and any commands that are allowed must be explicitly specified in the workflow
5050
- **Explicit tool allowlisting** - only tools explicitly allowed in the workflow can be used
51+
- **Engine network restrictions** - control network access for AI engines using domain allowlists
5152
- **Limit workflow longevity** - workflows can be configured to stop triggering after a certain time period
5253
- **Limit chat iterations** - workflows can be configured to limit the number of chat iterations per run, preventing runaway loops and excessive resource consumption
5354

@@ -211,6 +212,63 @@ Protect against model manipulation through layered defenses:
211212
- **Input sanitization**: Minimize untrusted content exposure; strip embedded commands when not required for functionality
212213
- **Action validation**: Implement a plan-validate-execute flow where policy layers check each tool call against risk thresholds
213214

215+
## Engine Network Permissions
216+
217+
### Overview
218+
219+
Engine network permissions provide fine-grained control over network access for AI engines themselves, separate from MCP tool network permissions. This feature uses Claude Code's hook system to enforce domain-based access controls.
220+
221+
### Security Benefits
222+
223+
1. **Defense in Depth**: Additional layer beyond MCP tool restrictions
224+
2. **Compliance**: Meet organizational security requirements for AI network access
225+
3. **Audit Trail**: Network access attempts are logged through Claude Code hooks
226+
4. **Principle of Least Privilege**: Only grant network access to required domains
227+
228+
### Implementation Details
229+
230+
- **Hook-Based Enforcement**: Uses Claude Code's PreToolUse hooks to intercept network requests
231+
- **Runtime Validation**: Domain checking happens at request time, not compilation time
232+
- **Error Handling**: Blocked requests receive clear error messages with allowed domains
233+
- **Performance Impact**: Minimal overhead (~10ms per network request)
234+
235+
### Best Practices
236+
237+
1. **Always Specify Permissions**: When using network features, explicitly list allowed domains
238+
2. **Use Wildcards Carefully**: `*.example.com` matches any subdomain including nested ones (e.g., `api.example.com`, `nested.api.example.com`) - ensure this broad access is intended
239+
3. **Test Thoroughly**: Verify that all required domains are included in allowlist
240+
4. **Monitor Usage**: Review workflow logs to identify any blocked legitimate requests
241+
5. **Document Reasoning**: Comment why specific domains are required for maintenance
242+
243+
### Permission Modes
244+
245+
1. **No network permissions**: Unrestricted access (backwards compatible)
246+
```yaml
247+
engine:
248+
id: claude
249+
# No permissions block - full network access
250+
```
251+
252+
2. **Empty allowed list**: Complete network access denial
253+
```yaml
254+
engine:
255+
id: claude
256+
permissions:
257+
network:
258+
allowed: [] # Deny all network access
259+
```
260+
261+
3. **Specific domains**: Granular access control to listed domains only
262+
```yaml
263+
engine:
264+
id: claude
265+
permissions:
266+
network:
267+
allowed:
268+
- "api.github.com"
269+
- "*.company-internal.com"
270+
```
271+
214272
## Engine Security Notes
215273

216274
Different agentic engines have distinct defaults and operational surfaces.
@@ -219,10 +277,11 @@ Different agentic engines have distinct defaults and operational surfaces.
219277

220278
- Restrict `claude.allowed` to only the needed capabilities (Edit/Write/WebFetch/Bash with a short list)
221279
- Keep `allowed_tools` minimal in the compiled step; review `.lock.yml` outputs
280+
- Use engine network permissions to restrict WebFetch and WebSearch to required domains only
222281

223282
#### Security posture differences with Codex
224283

225-
Claude exposes richer default tools and optional Bash; codex relies more on CLI behaviors. In both cases, tool allow-lists and pinned dependencies are your primary controls.
284+
Claude exposes richer default tools and optional Bash; codex relies more on CLI behaviors. In both cases, tool allow-lists, network restrictions, and pinned dependencies are your primary controls.
226285

227286
## See also
228287

go.mod

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ require (
1414
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
1515
github.com/sourcegraph/conc v0.3.0
1616
github.com/spf13/cobra v1.9.1
17-
gopkg.in/yaml.v3 v3.0.1
1817
)
1918

2019
require (
@@ -27,7 +26,6 @@ require (
2726
github.com/fatih/color v1.7.0 // indirect
2827
github.com/henvic/httpretty v0.1.4 // indirect
2928
github.com/inconshreveable/mousetrap v1.1.0 // indirect
30-
github.com/kr/text v0.2.0 // indirect
3129
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
3230
github.com/mattn/go-colorable v0.1.13 // indirect
3331
github.com/mattn/go-runewidth v0.0.16 // indirect

0 commit comments

Comments
 (0)