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
1 change: 1 addition & 0 deletions .github/agents/agentic-workflows.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,5 @@ gh aw compile --validate
- Workflows must be compiled to `.lock.yml` files before running in GitHub Actions
- **Bash tools are enabled by default** - Don't restrict bash commands unnecessarily since workflows are sandboxed by the AWF
- Follow security best practices: minimal permissions, explicit network access, no template injection
- **Network configuration**: Use ecosystem identifiers (`node`, `python`, `go`, etc.) or explicit FQDNs in `network.allowed`. Bare shorthands like `npm` or `pypi` are **not** valid. See https://github.com/github/gh-aw/blob/main/.github/aw/network.md for the full list of valid ecosystem identifiers and domain patterns.
- **Single-file output**: When creating a workflow, produce exactly **one** workflow `.md` file. Do not create separate documentation files (architecture docs, runbooks, usage guides, etc.). If documentation is needed, add a brief `## Usage` section inside the workflow file itself.
176 changes: 176 additions & 0 deletions .github/aw/network.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
---
description: Network access configuration reference for gh-aw workflows — valid ecosystem identifiers, domain patterns, and common mistakes to avoid.
---

# Network Access Configuration

Use the `network` frontmatter field to control which domains an AI engine can reach during a workflow run. All traffic is enforced by the Agent Workflow Firewall (AWF).
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

The doc says all traffic is enforced by the Agent Workflow Firewall (AWF), but gh-aw can run with the firewall/sandbox disabled (e.g., sandbox.agent: false / deprecated network.firewall: false). In those cases network.allowed still affects URL sanitization but not egress enforcement—please soften/clarify this sentence so readers don’t assume enforcement is guaranteed.

Suggested change
Use the `network` frontmatter field to control which domains an AI engine can reach during a workflow run. All traffic is enforced by the Agent Workflow Firewall (AWF).
Use the `network` frontmatter field to control which domains an AI engine can reach during a workflow run. When the Agent Workflow Firewall (AWF) is enabled, it enforces these settings for outbound traffic; when disabled, this configuration still affects URL sanitization but does not itself guarantee network egress enforcement.

Copilot uses AI. Check for mistakes.

## Quick Reference

```yaml
# Shorthand — use default infrastructure domains only
network: defaults

# Custom — allow defaults plus package registries for a Node.js project
network:
allowed:
- defaults
- node

# Custom — allow specific external APIs
network:
allowed:
- defaults
- api.example.com
- "*.trusted-partner.com"

# No network access
network:
allowed: []
```

## Valid Values for `network.allowed`

Each entry in `network.allowed` must be one of:

| Type | Examples | Notes |
|---|---|---|
| **Ecosystem identifier** | `defaults`, `node`, `python` | Expands to a curated list of domains for that runtime/tool |
| **Exact domain** | `api.example.com`, `registry.npmjs.org` | Must be a fully-qualified domain name (FQDN) |
| **Wildcard subdomain** | `*.example.com` | Matches `sub.example.com`, `deep.nested.example.com`, and `example.com` itself |

> ⚠️ **Bare shorthands like `npm`, `pypi`, or `localhost` are NOT valid** unless they are listed in the ecosystem identifiers table below. Use ecosystem identifiers (`node`, `python`) or explicit FQDNs (`registry.npmjs.org`, `pypi.org`) instead.
Comment on lines +40 to +43
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

“Exact domain” entries aren’t limited to FQDNs in the current implementation (single-label hostnames like localhost and IP literals like 127.0.0.1 are accepted/used). Consider rewording this row to “hostname/domain (no scheme; may be single-label like localhost)” to match actual validation behavior.

Suggested change
| **Exact domain** | `api.example.com`, `registry.npmjs.org` | Must be a fully-qualified domain name (FQDN) |
| **Wildcard subdomain** | `*.example.com` | Matches `sub.example.com`, `deep.nested.example.com`, and `example.com` itself |
> ⚠️ **Bare shorthands like `npm`, `pypi`, or `localhost` are NOT valid** unless they are listed in the ecosystem identifiers table below. Use ecosystem identifiers (`node`, `python`) or explicit FQDNs (`registry.npmjs.org`, `pypi.org`) instead.
| **Hostname / domain** | `api.example.com`, `registry.npmjs.org`, `localhost`, `127.0.0.1` | Hostname or domain (no scheme); may be single-label (like `localhost`) or an IP literal |
| **Wildcard subdomain** | `*.example.com` | Matches `sub.example.com`, `deep.nested.example.com`, and `example.com` itself |
> ⚠️ **Bare ecosystem-like shorthands such as `npm` or `pypi` are NOT valid** unless they are listed in the ecosystem identifiers table below. Use ecosystem identifiers (`node`, `python`) or explicit hostnames/domains (`registry.npmjs.org`, `pypi.org`, `localhost`) instead.

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

This warning groups localhost with invalid shorthands. However localhost is a valid explicit allowed entry today (it will match requests to the localhost hostname); what’s not supported is using it as an ecosystem identifier, and it won’t cover 127.0.0.1/::1. Suggest reframing to “localhost is not an ecosystem identifier; prefer local if you want to allow all loopback forms.”

Suggested change
> ⚠️ **Bare shorthands like `npm`, `pypi`, or `localhost` are NOT valid** unless they are listed in the ecosystem identifiers table below. Use ecosystem identifiers (`node`, `python`) or explicit FQDNs (`registry.npmjs.org`, `pypi.org`) instead.
> ⚠️ **Bare shorthands like `npm` or `pypi` are NOT valid ecosystem identifiers unless they are listed in the ecosystem identifiers table below. `localhost` is not an ecosystem identifier; prefer `local` if you want to allow all loopback forms.** Use ecosystem identifiers (`node`, `python`) or explicit FQDNs (`registry.npmjs.org`, `pypi.org`) instead.

Copilot uses AI. Check for mistakes.

## Ecosystem Identifiers

These keywords expand to curated lists of domains maintained by gh-aw:

| Identifier | Runtime / Tool | Key Domains Enabled |
Comment on lines +45 to +49
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

The table claims to list all supported ecosystem identifiers, but it’s missing the supported compound identifier default-safe-outputs (see pkg/workflow/domains.go compoundEcosystems) which also expands via the same mechanism as network.allowed. Either include it (with a note it’s primarily intended for safe-outputs.allowed-domains) or adjust the “complete list” wording/count.

Copilot uses AI. Check for mistakes.
|---|---|---|
| `defaults` | Basic infrastructure | Certificate authorities, Ubuntu package verification, JSON schema |
| `github` | GitHub domains | `*.githubusercontent.com`, `codeload.github.com`, `docs.github.com` |
| `github-actions` | GitHub Actions artifacts | Azure Blob storage for action caches and artifacts |
| `node` | npm / yarn / pnpm | `registry.npmjs.org`, `npmjs.com`, `yarnpkg.com` |
| `python` | pip / PyPI / conda | `pypi.org`, `files.pythonhosted.org`, `pip.pypa.io` |
| `go` | Go modules | `proxy.golang.org`, `sum.golang.org`, `go.dev` |
| `dotnet` | NuGet / .NET | `api.nuget.org`, `nuget.org`, `dotnet.microsoft.com` |
| `java` | Maven / Gradle | `repo1.maven.org`, `plugins.gradle.org`, `jdk.java.net` |
| `ruby` | Bundler / RubyGems | `rubygems.org`, `api.rubygems.org` |
| `rust` | Cargo | `crates.io`, `index.crates.io`, `static.crates.io`, `sh.rustup.rs` |
| `swift` | Swift Package Manager | `swift.org`, `cocoapods.org` |
| `php` | Composer / Packagist | `packagist.org`, `repo.packagist.org`, `getcomposer.org` |
| `dart` | pub.dev | `pub.dev`, `pub.dartlang.org` |
| `haskell` | Hackage / GHCup | `*.hackage.haskell.org`, `get-ghcup.haskell.org` |
| `perl` | CPAN | `cpan.org`, `metacpan.org` |
| `containers` | Docker / GHCR | `ghcr.io`, `registry.hub.docker.com`, `*.docker.io` |
| `playwright` | Playwright browsers | `playwright.download.prss.microsoft.com`, `cdn.playwright.dev` |
| `linux-distros` | apt / yum / apk | `deb.debian.org`, `security.debian.org`, Ubuntu/Alpine mirrors |
| `terraform` | HashiCorp | `releases.hashicorp.com`, `registry.terraform.io` |
| `local` | Loopback addresses | `127.0.0.1`, `::1`, `localhost` |
| `bazel` | Bazel build | `releases.bazel.build`, `bcr.bazel.build` |
| `clojure` | Clojure / Clojars | `clojars.org`, `repo.clojars.org` |
| `deno` | Deno / JSR | `deno.land`, `jsr.io` |
| `elixir` | Hex.pm | `hex.pm`, `repo.hex.pm` |
| `fonts` | Google Fonts | `fonts.googleapis.com`, `fonts.gstatic.com` |
| `julia` | Julia packages | `pkg.julialang.org`, `julialang.org` |
| `kotlin` | Kotlin / JetBrains | `packages.jetbrains.team` |
| `lua` | LuaRocks | `luarocks.org` |
| `node-cdns` | JS CDNs | `cdn.jsdelivr.net`, `code.jquery.com`, `unpkg.com` |
| `ocaml` | OPAM | `opam.ocaml.org`, `ocaml.org` |
| `powershell` | PowerShell Gallery | `powershellgallery.com` |
| `r` | CRAN | `cran.r-project.org`, `cloud.r-project.org` |
| `scala` | sbt / Scala | `repo.scala-sbt.org`, `repo1.maven.org` |
| `zig` | Zig packages | `ziglang.org` |
| `dev-tools` | CI/CD tools | Renovate, Codecov, shields.io, and other dev tooling |
| `chrome` | Chrome / Chromium | `*.googleapis.com`, `*.gvt1.com` |

## Invalid Shorthands

These values look like they might work but are **not valid** ecosystem identifiers and will be passed through as literal domain names (and will almost certainly not match any real host):

| Invalid value | What you probably meant | Correct value |
|---|---|---|
| `npm` | npm registry | `node` |
| `pypi` | Python Package Index | `python` |
| `pip` | pip package manager | `python` |
| `cargo` | Rust crate registry | `rust` |
| `gem` or `gems` | RubyGems | `ruby` |
| `nuget` | NuGet package registry | `dotnet` |
| `maven` | Maven Central | `java` |
| `gradle` | Gradle plugins | `java` |
| `composer` | PHP Composer | `php` |
| `docker` | Docker Hub / GHCR | `containers` |
| `localhost` | Loopback interface | `local` |

## Domain Pattern Rules

- **Wildcard `*` requires a dot prefix**: `*.example.com` is valid; bare `*` is blocked (and rejected outright in strict mode).
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

This bullet implies bare * is blocked, but * is treated as an allow-all sentinel outside strict mode (validation explicitly skips it), and strict mode only rejects standalone * entries. Consider updating this guidance to distinguish: * (allow all; discouraged; rejected in strict mode) vs *.example.com (scoped wildcard).

Suggested change
- **Wildcard `*` requires a dot prefix**: `*.example.com` is valid; bare `*` is blocked (and rejected outright in strict mode).
- **Wildcard usage**: `*.example.com` is a valid scoped wildcard. A bare `*` acts as an allow-all sentinel outside strict mode (discouraged) and is rejected outright in strict mode.

Copilot uses AI. Check for mistakes.
- **Protocol prefix is not supported**: `https://api.example.com` is not a valid entry — omit the scheme and write `api.example.com`.
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

This bullet says protocol prefixes aren’t supported, but network.allowed currently allows http:// and https:// prefixes for protocol-specific filtering (see pkg/workflow/safe_outputs_validation.go:121-141 and the existing reference docs at docs/src/content/docs/reference/network.md#protocol-specific-domain-filtering). Please update this rule to reflect current supported syntax.

Suggested change
- **Protocol prefix is not supported**: `https://api.example.com` is not a valid entry — omit the scheme and write `api.example.com`.
- **Optional `http://` or `https://` prefix only**: `api.example.com`, `https://api.example.com`, and `http://api.example.com` are all valid entries; other schemes (for example, `ws://`, `wss://`, `ftp://`) are not supported.

Copilot uses AI. Check for mistakes.
- **Subdomains must be explicit**: `github.com` does not cover `api.github.com`; use `*.github.com` or add both entries.
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

This rule says github.com does not cover api.github.com, but gh-aw treats an allowed base domain as allowing all its subdomains (and the official docs state the same). Please correct this to avoid readers over-permitting with unnecessary wildcards or duplicating entries.

Suggested change
- **Subdomains must be explicit**: `github.com` does not cover `api.github.com`; use `*.github.com` or add both entries.
- **Base domains also cover subdomains**: allowing `github.com` also allows `api.github.com`; you do not need `*.github.com` or duplicate entries.

Copilot uses AI. Check for mistakes.

## Inferring the Right Ecosystem From Repository Files

When a workflow builds, tests, or installs packages, always add the matching ecosystem alongside `defaults`:

| File indicators | Ecosystem to add | Enables |
|---|---|---|
| `package.json`, `yarn.lock`, `pnpm-lock.yaml`, `.nvmrc` | `node` | `registry.npmjs.org` |
| `requirements.txt`, `pyproject.toml`, `uv.lock`, `Pipfile` | `python` | `pypi.org`, `files.pythonhosted.org` |
| `go.mod`, `go.sum` | `go` | `proxy.golang.org`, `sum.golang.org` |
| `*.csproj`, `*.sln`, `*.slnx` | `dotnet` | `api.nuget.org` |
| `pom.xml`, `build.gradle` | `java` | `repo1.maven.org` |
| `Gemfile`, `*.gemspec` | `ruby` | `rubygems.org` |
| `Cargo.toml` | `rust` | `crates.io` |
| `Package.swift` | `swift` | `swift.org` |
| `composer.json` | `php` | `packagist.org` |
| `pubspec.yaml` | `dart` | `pub.dev` |

> ⚠️ **`network: defaults` alone is never sufficient for code workflows** — `defaults` covers basic infrastructure (certificate authorities, Ubuntu verification) but cannot reach package registries. Always add the language ecosystem identifier.

## Common Patterns

### Workflow that reads GitHub data only

```yaml
network:
allowed:
- defaults
- github
```

### Node.js CI workflow

```yaml
network:
allowed:
- defaults
- node
```

### Multi-language project

```yaml
network:
allowed:
- defaults
- node
- python
```

### Calling an external API

```yaml
network:
allowed:
- defaults
- api.myservice.com
- "*.myservice.com"
```

### No outbound network access

```yaml
network:
allowed: []
```
Loading