Engine configuration
Engine Configuration
Section titled “Engine Configuration”The engine field specifies which engine to use for the agentic task. The string form is an engine identifier (currently only copilot is supported). The object form uses id for the engine identifier plus additional options like model selection and timeout.
# Simple string format (engine identifier, defaults to copilot)engine: copilot
# Object format with additional optionsengine: id: copilot model: claude-opus-4.7 timeout-minutes: 30Fields
Section titled “Fields”| Field | Type | Default | Description |
|---|---|---|---|
id |
string | copilot |
Engine identifier. Currently only copilot (GitHub Copilot CLI) is supported. |
model |
string | claude-opus-4.7 |
AI model to pass to the Copilot CLI --model flag. Any model ID supported by GitHub Copilot is accepted (e.g., claude-sonnet-4.5, claude-opus-4.7). The compiler does not validate the value — an unrecognised ID produces a runtime error from the CLI. |
timeout-minutes |
integer | (none) | Maximum time in minutes the agent job is allowed to run. Sets timeoutInMinutes on the Agent job in the generated pipeline. |
version |
string | (none) | Engine CLI version to install (e.g., "1.0.43", "latest"). Overrides the pinned COPILOT_CLI_VERSION. Set to "latest" to use the newest available version. |
agent |
string | (none) | Custom agent file identifier (Copilot only). Adds --agent <name> to the CLI invocation, selecting a custom agent from .github/agents/. |
api-target |
string | (none) | Custom API endpoint hostname for GHES/GHEC (e.g., "api.acme.ghe.com"). Adds --api-target <hostname> to the CLI invocation and adds the hostname to the AWF network allowlist. |
args |
list | [] |
Custom CLI arguments appended after compiler-generated args. Subject to shell-safety validation and blocked from overriding compiler-controlled flags (see args reference below). |
env |
map | (none) | Engine-specific environment variables merged into the sandbox step’s env: block. Keys must be valid env var names; values must not contain ADO expressions ($(, ${{) or pipeline command injection (##vso[). Compiler-controlled keys are blocked (see env reference below). |
command |
string | (none) | Custom engine executable path (skips the default engine binary installation). The path must be accessible inside the AWF container (e.g., /tmp/... or workspace-mounted paths). |
github-app-token |
map | (none) | GitHub App-backed Copilot authentication. When set, the compiler mints a short-lived installation token at runtime and sources GITHUB_TOKEN from it instead of the operator-provided secret variable. See github-app-token below. Copilot engine only — rejected at compile time for any other engine.id. |
timeout-minutes
Section titled “timeout-minutes”The timeout-minutes field sets a wall-clock limit (in minutes) for the entire agent job. It maps to the Azure DevOps timeoutInMinutes job property on Agent. This is useful for:
- Budget enforcement – hard-capping the total runtime of an agent to control compute costs.
- Pipeline hygiene – preventing agents from occupying a runner indefinitely if they stall or enter long retry loops.
- SLA compliance – ensuring scheduled agents complete within a known window.
When omitted, Azure DevOps uses its default job timeout (60 minutes). When set, the compiler emits timeoutInMinutes: <value> on the agentic job.
The args list appends raw CLI arguments to the Copilot invocation. This is an escape hatch for passing flags that ado-aw does not yet model in front matter — use it sparingly.
The compiler rejects any argument that starts with one of the following blocked prefixes, because those flags are owned and managed by the compiler:
| Blocked prefix | Reason |
|---|---|
--prompt |
Compiler controls how the prompt is supplied |
--additional-mcp-config |
Compiler owns MCP configuration |
--allow-tool |
Compiler controls tool allow-listing |
--allow-all-tools |
Compiler controls tool allow-listing |
--allow-all-paths |
Compiler controls path permissions |
--disable-builtin-mcps |
Compiler manages built-in MCP setup |
--no-ask-user |
Compiler controls interactive-mode setting |
--ask-user |
Compiler controls interactive-mode setting |
Each argument is also checked against a shell-safety character allowlist to prevent injection.
Example — enabling a hypothetical experimental flag:
engine: id: copilot args: - --experimental-feature - --log-level=debugThe env map injects additional environment variables into the sandbox step’s env: block. This is useful for passing static configuration values or feature flags that the agent script needs.
The compiler also blocks keys that it controls:
| Blocked key | Reason |
|---|---|
GITHUB_TOKEN |
Compiler-managed auth token |
GITHUB_READ_ONLY |
Compiler-managed auth mode |
COPILOT_OTEL_ENABLED |
Compiler-managed telemetry |
COPILOT_OTEL_EXPORTER_TYPE |
Compiler-managed telemetry |
COPILOT_OTEL_FILE_EXPORTER_PATH |
Compiler-managed telemetry |
PATH |
System shell variable |
HOME |
System shell variable |
BASH_ENV |
System shell variable |
ENV |
System shell variable |
IFS |
System shell variable |
LD_PRELOAD |
Dynamic linker — security-sensitive |
LD_LIBRARY_PATH |
Dynamic linker — security-sensitive |
Example — passing static configuration values:
engine: id: copilot env: STATIC_CONFIG: "production" FEATURE_FLAGS: "enable-new-parser,strict-mode"github-app-token
Section titled “github-app-token”By default the Copilot engine authenticates using the GITHUB_TOKEN pipeline
variable you store with ado-aw secrets set GITHUB_TOKEN <pat>. For
organization-managed Copilot access you can instead have the compiler mint a
GitHub App installation token at pipeline runtime — mirroring
gh-aw’s create-github-app-token model,
adapted to Azure DevOps.
engine: id: copilot github-app-token: app-id: 1234567 # literal App ID or client ID (required) owner: octo-org # installation owner (org or user login; required) repositories: [octo-repo] # optional — scopes the token to these repos only # api-url: https://ghe.example.com/api/v3 # optional — GHES base URL # skip-token-revocation: false # optional — revoke token after use (default) # private-key: MY_SECRET_VAR # optional — override the default variable nameStore the App’s private key once before running the pipeline:
ado-aw secrets set GITHUB_APP_PRIVATE_KEY "$(cat app-private-key.pem)"Fields:
| Field | Required | Description |
|---|---|---|
app-id |
Yes | The GitHub App ID — a literal value: either a numeric App ID (e.g. 1234567, quoted or unquoted) or an alphanumeric client ID (e.g. Iv23liABC…). The App ID is not secret so it is written verbatim. |
owner |
Yes | GitHub installation owner — organization or user login. |
repositories |
No | Owner-relative repository names to scope the token to. Omit to span every repository the installation grants. |
api-url |
No | GitHub API base URL. Defaults to https://api.github.com. For GitHub Enterprise Server, set the /api/v3 base URL (e.g. https://ghe.example.com/api/v3). Must be an https:// URL. |
skip-token-revocation |
No | When true, do not revoke the minted token after the Copilot run. Defaults to false (token revoked after use). |
private-key |
No | Name of the ADO secret pipeline variable holding the private key (PEM). Defaults to GITHUB_APP_PRIVATE_KEY. Set this only to point at a differently-named variable. |
What the compiler generates:
- A token-mint step runs immediately before the Copilot invocation in both the Agent and Detection jobs. It builds a short-lived RS256 JWT, resolves the GitHub App installation for
owner, exchanges it for a scoped installation token, and exposes it as a masked same-job variable (GITHUB_APP_TOKEN). - The Copilot engine’s
GITHUB_TOKENis sourced from$(GITHUB_APP_TOKEN)instead of the operator-provided static variable. - A token-revocation step runs after the Copilot invocation (unless
skip-token-revocation: true), callingDELETE /installation/token. It is best-effort (always()+continueOnError) and never fails the build. - The minted token is never provided to SafeOutputs, user-authored
steps:, Teardown, ManualReview, or Conclusion.
The mint and revocation steps run outside the AWF network sandbox — they reach the GitHub API over the build agent pool’s normal network, so no network.allowed entry is needed.
Copilot model provider (BYOK) configuration
Section titled “Copilot model provider (BYOK) configuration”The Copilot engine can route requests to an external LLM provider — for example
a private Azure Copilot Foundry instance — instead of GitHub’s default
routing. This Bring Your Own Key (BYOK) mode is configured with the
dedicated engine.provider block, which the compiler maps to the
COPILOT_PROVIDER_* environment variables the Copilot CLI reads to reach the
provider.
Prefer engine.provider over hand-writing COPILOT_PROVIDER_* keys in
engine.env: it is typed and validated, and its token sub-block lets the
compiler acquire the provider bearer token for you, minted in the same
job as each engine run so it resolves correctly at runtime.
engine.provider fields
Section titled “engine.provider fields”| Field | Required | Maps to | Description |
|---|---|---|---|
base-url |
yes | COPILOT_PROVIDER_BASE_URL |
Base URL of the external provider (e.g. https://RESOURCE.cognitiveservices.azure.com/openai/v1). A literal host is auto-added to the AWF network allowlist. |
type |
optional | COPILOT_PROVIDER_TYPE |
Provider format: openai (default), azure, or anthropic. |
wire-api |
optional | COPILOT_PROVIDER_WIRE_API |
Wire API variant: completions (default) or responses. |
token |
optional | COPILOT_PROVIDER_API_KEY |
Compiler-minted credential via Azure CLI (see below). Mutually exclusive with api-key. |
api-key |
optional | COPILOT_PROVIDER_API_KEY |
Static API key, typically a $(VAR) secret pipeline variable. Mutually exclusive with token. |
The model itself is set via engine.model (or a COPILOT_MODEL env var).
Compiler-owned token acquisition (provider.token)
Section titled “Compiler-owned token acquisition (provider.token)”Set provider.token to have the compiler mint the provider bearer token in-job
via Azure CLI + an ARM service connection:
token field |
Required | Description |
|---|---|---|
service-connection |
yes | ARM service connection used to authenticate az before minting the token. |
resource |
optional | Azure resource (audience) for az account get-access-token --resource. Defaults to https://cognitiveservices.azure.com. |
The compiler emits an AzureCLI@2 step immediately before the Copilot
invocation in both the Agent and Detection jobs. That step runs
az account get-access-token and publishes the result as a same-job secret
pipeline variable (AW_PROVIDER_BEARER_TOKEN), which is wired into
COPILOT_PROVIDER_API_KEY — the credential env var the AWF api-proxy sidecar
reads and forwards as Authorization: Bearer <value>. Because the token is
minted in the same job as the engine run, it resolves via a plain $(...) macro
— no cross-job output plumbing, no dependsOn.
The minted token is a short-lived AAD access token (typically valid ~1 hour). The mint step is emitted as the last step before the engine invocation to keep it fresh; a pool that queues or idles for the full token lifetime between the mint step and the run could observe an expired token.
Credential isolation
Section titled “Credential isolation”When a provider credential is configured (base-url + token/api-key), the
compiler automatically enables the AWF api-proxy sidecar
(--enable-api-proxy) and pre-pulls its container image. The real credential is
held inside the proxy container; the agent container receives only a placeholder
and a proxy URL, and the credential keys are passed as --exclude-env flags so
the raw value is never copied into the agent via --env-all. This applies to
both the Agent and Detection (threat-analysis) jobs.
Network allowlist
Section titled “Network allowlist”When base-url is a literal URL, the compiler automatically adds its
hostname to the AWF network allowlist. If a literal value cannot be resolved to
a DNS-safe host, the compiler emits a non-fatal warning telling you to add the
provider hostname manually via network.allowed.
Example — Azure Copilot Foundry with a compiler-minted bearer token
Section titled “Example — Azure Copilot Foundry with a compiler-minted bearer token”engine: id: copilot model: gpt-4o provider: base-url: https://my-foundry.cognitiveservices.azure.com/openai/v1 type: azure token: service-connection: my-arm-connection # resource: https://cognitiveservices.azure.com # optional; this is the defaultThe compiler mints the token in-job (Agent + Detection) and adds
my-foundry.cognitiveservices.azure.com to the AWF allowlist automatically. No
setup: step or COPILOT_PROVIDER_* env keys are needed.
To use a static key instead, drop token and set api-key to a secret
variable:
engine: id: copilot provider: base-url: https://api.openai.com/v1 type: openai api-key: $(OPENAI_API_KEY)Raw engine.env COPILOT_PROVIDER_* (legacy, discouraged)
Section titled “Raw engine.env COPILOT_PROVIDER_* (legacy, discouraged)”For back-compat you may still set COPILOT_PROVIDER_* keys directly in
engine.env. engine.provider and raw COPILOT_PROVIDER_* keys are mutually
exclusive — setting both is a compile error. A cross-job macro such as
$(Setup.FOUNDRY_TOKEN) (a value set with isOutput=true in a separate
setup: job) does not resolve inside a step env: block and yields an empty
token at runtime — use provider.token (or a same-job / pipeline /
variable-group $(VAR) secret) instead.