Skip to content

Network isolation and permissions

Network isolation is provided by AWF (Agentic Workflow Firewall), which provides L7 (HTTP/HTTPS) egress filtering using a rootless Docker topology. AWF restricts network access to an allowlist of approved domains.

Generated pipelines run AWF in strict topology mode: both the Agent and Detection jobs invoke AWF rootlessly with --network-isolation — there is no sudo, --enable-host-access, or legacy-security fallback. The Agent additionally passes --topology-attach awmg-mcpg so the trusted MCP Gateway container is reachable inside AWF’s internal network; the agent has no route to the build-agent host. Detection runs without MCPG attachment.

The ado-aw compiler binary is distributed via GitHub Releases with SHA256 checksum verification. The AWF binary is distributed via GitHub Releases with SHA256 checksum verification. Docker is sourced via the DockerInstaller@0 ADO task.

The following domains are always allowed, defined in CORE_ALLOWED_HOSTS in allowed_hosts.rs. Under AWF’s strict topology, host.docker.internal is deliberately not on this list — the agent has no route to the build-agent host, and SafeOutputs runs as a hardened sibling container inside MCPG, not as a host-side process:

Host Pattern Purpose
dev.azure.com, *.dev.azure.com Azure DevOps
vstoken.dev.azure.com Azure DevOps tokens
vssps.dev.azure.com Azure DevOps identity
*.visualstudio.com Visual Studio services
*.vsassets.io Visual Studio assets
*.vsblob.visualstudio.com Visual Studio blob storage
*.vssps.visualstudio.com Visual Studio identity
pkgs.dev.azure.com, *.pkgs.dev.azure.com Azure DevOps Artifacts/NuGet
aex.dev.azure.com, aexus.dev.azure.com Azure DevOps CDN
vsrm.dev.azure.com, *.vsrm.dev.azure.com Visual Studio Release Management
github.com GitHub main site
api.github.com GitHub API
*.githubusercontent.com GitHub raw content
*.github.com GitHub services
*.copilot.github.com GitHub Copilot
*.githubcopilot.com GitHub Copilot
copilot-proxy.githubusercontent.com GitHub Copilot proxy
login.microsoftonline.com Microsoft identity (OAuth)
login.live.com Microsoft account authentication
login.windows.net Azure AD authentication
*.msauth.net, *.msftauth.net Microsoft authentication assets
*.msauthimages.net Microsoft authentication images
graph.microsoft.com Microsoft Graph API
management.azure.com Azure Resource Manager
*.blob.core.windows.net Azure Blob storage
*.table.core.windows.net Azure Table storage
*.queue.core.windows.net Azure Queue storage
*.applicationinsights.azure.com Application Insights telemetry
*.in.applicationinsights.azure.com Application Insights ingestion
dc.services.visualstudio.com Visual Studio telemetry
rt.services.visualstudio.com Visual Studio runtime telemetry
config.edge.skype.com Configuration
aka.ms Microsoft link shortener (used by az subcommand help/metadata) — contributed by the always-on Azure CLI extension

Agents can specify additional allowed hosts in their front matter using either ecosystem identifiers or raw domain patterns:

network:
allowed:
- python # Ecosystem identifier -- expands to Python/PyPI domains
- rust # Ecosystem identifier -- expands to Rust/crates.io domains
- "*.mycompany.com" # Raw domain pattern
- "api.external-service.com" # Raw domain

Ecosystem identifiers are shorthand names that expand to curated domain lists for common language ecosystems and services. The domain lists are sourced from gh-aw and kept up to date via an automated workflow.

Available ecosystem identifiers include:

Identifier Includes
defaults Certificate infrastructure, Ubuntu mirrors, common package registries
github GitHub domains (github.com, *.githubusercontent.com, etc.)
local Loopback addresses (localhost, 127.0.0.1, ::1)
containers Docker Hub, GHCR, Quay, Kubernetes
linux-distros Debian, Alpine, Fedora, CentOS, Arch Linux package repositories
dev-tools CI/CD and developer tool services (Codecov, Shields.io, Snyk, etc.)
python PyPI, pip, Conda, Anaconda
rust crates.io, rustup, static.rust-lang.org
node npm, Yarn, pnpm, Bun, Deno, Node.js
go proxy.golang.org, pkg.go.dev, Go module proxy
java Maven Central, Gradle, JDK downloads
dotnet NuGet, .NET SDK
ruby RubyGems, Bundler
swift Swift.org, CocoaPods
terraform HashiCorp releases, Terraform registry

Additional ecosystems: bazel, chrome, clojure, dart, deno, elixir, fonts, github-actions, haskell, julia, kotlin, latex, lean, lua, node-cdns, ocaml, perl, php, playwright, powershell, python-native, r, scala, zig.

The full domain lists are defined in src/data/ecosystem_domains.json.

All hosts (core + ecosystem expansions + user-specified) are combined into a comma-separated domain list passed to AWF’s --allow-domains flag.

The network.blocked field removes hosts from the combined allowlist. Both ecosystem identifiers and raw domain strings are supported. Blocking an ecosystem identifier removes all of its domains. Blocking a raw domain uses exact-string matching – blocking "github.com" does not also remove "*.github.com".

network:
allowed:
- python
- node
blocked:
- python # Remove all Python ecosystem domains
- "github.com" # Remove exact domain
- "*.github.com" # Remove wildcard variant too

ADO does not support fine-grained permissions – there are two access levels: blanket read and blanket write. ARM service connections are used to mint scoped tokens for the agent (permissions.read) and optionally for the executor (permissions.write). The Stage 3 executor also uses the pipeline’s built-in $(System.AccessToken) as its default write token when no permissions.write override is configured.

Note: The trigger filter gate step (Setup job) uses System.AccessToken for two purposes: (1) self-cancelling the build when filters don’t match (PATCH to _apis/build/builds/{id}), and (2) fetching PR metadata for Tier 2 filters (labels, draft status, changed files). The Stage 3 executor also uses System.AccessToken as its default write token. In both cases the pipeline must have “Allow scripts to access the OAuth token” enabled. The agent (Stage 1) never receives System.AccessToken — this trust boundary ensures the AI agent cannot directly perform write operations.

permissions:
read: my-read-arm-connection # Stage 1 agent -- read-only ADO access
write: my-write-arm-connection # Stage 3 executor -- write access for safe-outputs
  • permissions.read: Mints a read-only ADO-scoped token given to the agent inside the AWF sandbox (Stage 1). The agent can query ADO APIs but cannot write.
  • permissions.write (optional): Overrides the Stage 3 executor’s default $(System.AccessToken) with an ARM-minted write token (SC_WRITE_TOKEN). Use this for cross-org or cross-project writes, or when you need the action attributed to a named service principal rather than the pipeline’s build service identity.
  • Both omitted: The agent has no ADO API access. Stage 3 still uses $(System.AccessToken) for write operations (sufficient for most same-project safe outputs).
# Agent can read ADO; executor writes via $(System.AccessToken) (default)
permissions:
read: my-read-sc
# Agent can read ADO; executor writes via named ARM identity
permissions:
read: my-read-sc
write: my-write-sc
# No ADO API read for agent; executor writes via named ARM identity
permissions:
write: my-write-sc