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
16 changes: 15 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,12 @@ index to jump to the right page.
- [`docs/ado-aw-debug.md`](docs/ado-aw-debug.md) — debug-only `ado-aw-debug:`
front-matter section (`skip-integrity`, `create-issue` for filing GitHub
issues from dogfood pipelines). NOT a regular safe-output.
- [`docs/supply-chain.md`](docs/supply-chain.md) — optional `supply-chain:`
front-matter section that mirrors the compiler, AWF binary, ado-script
bundle, and AWF/MCPG images from an internal Azure DevOps Artifacts feed
and/or container registry (NuGet `DownloadPackage@1` + ACR `az acr login`),
with asymmetric auth (feed defaults to `$(System.AccessToken)`; registry
requires a service connection).

### Compiler internals & operations

Expand Down Expand Up @@ -389,7 +395,15 @@ Following the gh-aw security model:
1. **Safe Outputs**: Only allow write operations through sanitized safe-output
declarations — see [`docs/safe-outputs.md`](docs/safe-outputs.md).
2. **Network Isolation**: Pipelines run in OneBranch's network-isolated
environment via AWF — see [`docs/network.md`](docs/network.md).
environment via AWF — see [`docs/network.md`](docs/network.md). **Scope
note:** AWF's L7 allowlist wraps *only* the agent's copilot command
(`awf … --allow-domains … -- '<engine_run>'` in
`src/compile/agentic_pipeline.rs::run_agent_step`). All other ADO steps —
binary/bundle downloads, `docker pull`, ACR/NuGet auth (including the
`supply-chain:` mirror fetches) — run *outside* the sandbox with the build
agent pool's normal network, so they do **not** need entries in the AWF
allowlist. Air-gapping the build agent itself from GitHub/GHCR is the agent
pool's network policy, not AWF.
3. **Tool Allow-listing**: Agents have access to a limited, controlled set of
tools — see [`docs/tools.md`](docs/tools.md) and
[`docs/mcp.md`](docs/mcp.md).
Expand Down
8 changes: 8 additions & 0 deletions docs/front-matter.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,14 @@ permissions: # optional ADO access token configuration
# Default: executor uses $(System.AccessToken).
# Set this only for cross-org writes or
# named-identity attribution.
supply-chain: # optional internal supply-chain mirror (see docs/supply-chain.md)
feed: # mirror binaries (compiler, AWF, ado-script) from an ADO Artifacts feed
name: my-project/my-feed # feed name or project/feed; scalar `feed: my-feed` shorthand also works
service-connection: feed-conn # optional; omit for same-org feeds (uses $(System.AccessToken))
registry: # mirror AWF/MCPG images from an internal ACR
name: myacr.azurecr.io/mirror # registry host or base path (artifact names kept under it)
service-connection: acr-conn # REQUIRED when registry is set (ACR has no System.AccessToken path)
service-connection: shared-conn # optional shared fallback for whichever target omits its own
parameters: # optional ADO runtime parameters (surfaced in UI when queuing a run)
- name: clearMemory
displayName: "Clear agent memory"
Expand Down
186 changes: 186 additions & 0 deletions docs/supply-chain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
# Internal Supply-Chain Mirror (`supply-chain:`)

By default a compiled agentic pipeline fetches four kinds of artifact from
GitHub / GHCR at run time:

| # | Artifact | Default source |
|---|----------|----------------|
| 1 | `ado-aw` compiler (`ado-aw-linux-x64`) | `github.com/githubnext/ado-aw` releases |
| 2 | AWF firewall (`awf-linux-x64`) | `github.com/github/gh-aw-firewall` releases |
| 3 | `ado-script.zip` bundle | `github.com/githubnext/ado-aw` releases |
| 4 | AWF + MCPG container images | `ghcr.io/github/...` |

The optional `supply-chain:` front-matter section reroutes these fetches to an
**internal Azure DevOps Artifacts feed** (for the binaries #1–#3) and/or an
**internal container registry** (for the images #4). This is intended for
supply-chain-hardened environments where the build agent pool cannot reach
GitHub / GHCR.

When `supply-chain:` is omitted, the generated pipeline is byte-for-byte
identical to before — there is no behavioural change for existing agents.

## Configuration

```yaml
supply-chain:
feed: # mirrors binaries #1, #2, #3
name: my-project/my-feed # feed name or "project/feed"
service-connection: feed-conn # optional (see Authentication)
registry: # mirrors images #4
name: myacr.azurecr.io/mirror # registry host or base path
service-connection: acr-conn # required when registry is set
service-connection: shared-conn # optional shared fallback for both targets
```

| Field | Type | Required | Purpose |
|-------|------|----------|---------|
| `feed` | scalar **or** `{ name, service-connection }` | optional | Enables the binary mirror (#1–#3). A bare string is shorthand for `{ name: <string> }`. |
| `registry` | scalar **or** `{ name, service-connection }` | optional | Enables the image mirror (#4). |
| `service-connection` | string | optional | Shared fallback connection used by whichever target does not declare its own. |

`feed` and `registry` are **independent** — set either, both, or neither.

### Scalar shorthand

A bare scalar is sugar for an object with no per-target connection:

```yaml
supply-chain:
feed: my-feed # same as { name: my-feed }
registry: myacr.azurecr.io
service-connection: shared-conn
```

## Authentication

Authentication is **asymmetric** because the two targets authenticate
differently:

### Feed (binaries)

The feed mirror uses `NuGetAuthenticate@1` + `DownloadPackage@1`. The effective
service connection resolves as:

1. the feed's own `service-connection`, else
2. the top-level `service-connection`, else
3. `$(System.AccessToken)` (the build service identity).

For a **same-organization** feed, no service connection is required: grant the
pipeline's build identity (e.g. `<Project> Build Service`) the **Feed Reader**
role and `NuGetAuthenticate@1` authenticates automatically via
`$(System.AccessToken)`. Set a `service-connection` only for cross-org or
external feeds.

### Registry (images)

The image mirror authenticates with `az acr login` (`AzureCLI@2`) using the
resolved service connection, then `docker pull`s the rewritten image
references. **`$(System.AccessToken)` cannot authenticate to a container
registry**, so a service connection **must** resolve when `registry` is set —
either `registry.service-connection` or the top-level `service-connection`.
Compilation fails otherwise:

```
supply-chain.registry requires a service connection: set
`registry.service-connection` or a top-level `supply-chain.service-connection`.
A container registry (ACR) cannot be accessed with $(System.AccessToken).
```

The registry connection is an ARM / Azure service connection (the same kind
used by `permissions:`), passed to `AzureCLI@2` as `azureSubscription`.

> **Private Link note:** the ACR name passed to `az acr login --name` is derived
> from the host portion of `registry.name`, assuming the standard
> `<name>.azurecr.io` login server. If your ACR is reached over Azure Private
> Link with a custom domain (e.g. `myacr.internal.contoso.com`), set
> `registry.name` to the canonical `*.azurecr.io` login server so the derived
> registry name is correct.

## What the feed and registry must contain

Versions stay **pinned by the generating compiler** — the internal mirror must
host the exact pinned versions. A mirror that is a few days behind is fine: use
the matching `ado-aw` compiler version.

### Feed packages (NuGet)

The feed must host these NuGet packages (same base names, **bare semver**
versions — no leading `v`):

| Package id | Version | Must contain |
|------------|---------|--------------|
| `ado-aw` | compiler version (e.g. `0.37.0`) | `ado-aw-linux-x64`, `checksums.txt` |
| `awf` | the AWF version (e.g. `0.27.3`) | `awf-linux-x64`, `checksums.txt` |
| `ado-script` | compiler version | `ado-script.zip`, `checksums.txt` |

A NuGet package is a renamed zip; the compiler unzips it and relocates the
payload, so the package simply needs to carry the same files (and matching
`checksums.txt`) that the GitHub release ships. **Checksum verification with
`sha256sum -c checksums.txt` is preserved**, so the mirror must ship the
matching `checksums.txt`.

### Registry images

`registry.name` is a registry **host or base path** — teams generally cannot
publish under GHCR's `github/...` namespace, so the original GHCR prefix is
**not** preserved. Only the **artifact name** (the final image-name segment)
is kept, placed directly under the configured base path at the **same tag**:

| GHCR source | Internal reference (base path `<registry>`) |
|-------------|---------------------------------------------|
| `ghcr.io/github/gh-aw-firewall/squid:<awf-version>` | `<registry>/squid:<awf-version>` |
| `ghcr.io/github/gh-aw-firewall/agent:<awf-version>` | `<registry>/agent:<awf-version>` |
| `ghcr.io/github/gh-aw-mcpg:v<mcpg-version>` | `<registry>/gh-aw-mcpg:v<mcpg-version>` |

`<registry>` may be a bare host (`myacr.azurecr.io`) or a host with an
arbitrary namespace path (`myacr.azurecr.io/oss-mirror`,
`contoso.azurecr.io/team/oss/mirror`). The contract is only that the artifact
names (`squid`, `agent`, `gh-aw-mcpg`) and tags remain unchanged under that
path. `az acr login` derives the ACR registry name from the host portion of
the base path.

## Examples

Mirror everything, two different connections:

```yaml
supply-chain:
feed:
name: my-project/my-internal-feed
service-connection: feed-conn
registry:
name: myacr.azurecr.io
service-connection: acr-conn
```

Binaries only, same-org feed (uses `$(System.AccessToken)`):

```yaml
supply-chain:
feed: my-internal-feed
```

Images only:

```yaml
supply-chain:
registry:
name: myacr.azurecr.io
service-connection: acr-conn
```

## Network isolation note

The mirror fetches (`NuGetAuthenticate@1`, `DownloadPackage@1`, `docker pull`,
`az acr login`) run as ordinary ADO steps on the build agent — **outside** the
AWF network-isolation sandbox, which wraps only the copilot agent command.
Consequently:

- The feed/registry hosts are **not** added to the agent's AWF
`--allow-domains` allowlist (the network-isolated agent never contacts them).
- True isolation of the build agent from GitHub / GHCR is enforced by the agent
pool's own network policy; the `supply-chain:` rerouting is what lets such a
locked-down pool succeed.

See also: [`docs/network.md`](network.md),
[`docs/front-matter.md`](front-matter.md).
1 change: 1 addition & 0 deletions site/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export default defineConfig({
{ label: 'Runtimes', slug: 'reference/runtimes' },
{ label: 'Safe Outputs', slug: 'reference/safe-outputs' },
{ label: 'ado-aw-debug', slug: 'reference/ado-aw-debug' },
{ label: 'Supply Chain', slug: 'reference/supply-chain' },
{ label: 'Targets', slug: 'reference/targets' },
{ label: 'Network', slug: 'reference/network' },
{ label: 'MCP', slug: 'reference/mcp' },
Expand Down
111 changes: 111 additions & 0 deletions site/src/content/docs/reference/supply-chain.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
title: "Supply Chain reference"
description: "Mirror the compiler, AWF binary, ado-script bundle, and container images from an internal Azure DevOps Artifacts feed and registry."
---

By default a compiled agentic pipeline fetches four kinds of artifact from
GitHub / GHCR at run time:

| # | Artifact | Default source |
| --- | --- | --- |
| 1 | `ado-aw` compiler (`ado-aw-linux-x64`) | `github.com/githubnext/ado-aw` releases |
| 2 | AWF firewall (`awf-linux-x64`) | `github.com/github/gh-aw-firewall` releases |
| 3 | `ado-script.zip` bundle | `github.com/githubnext/ado-aw` releases |
| 4 | AWF + MCPG container images | `ghcr.io/github/...` |

The optional `supply-chain:` front-matter section reroutes these fetches to an
**internal Azure DevOps Artifacts feed** (binaries #1–#3) and/or an **internal
container registry** (images #4). It is intended for supply-chain-hardened
environments where the build agent pool cannot reach GitHub / GHCR.

When `supply-chain:` is omitted, the generated pipeline is byte-for-byte
identical to before.

## Configuration

```yaml
supply-chain:
feed: # mirrors binaries #1, #2, #3
name: my-project/my-feed # feed name or "project/feed"
service-connection: feed-conn # optional (see Authentication)
registry: # mirrors images #4
name: myacr.azurecr.io/mirror # registry host or base path
service-connection: acr-conn # required when registry is set
service-connection: shared-conn # optional shared fallback for both targets
```

| Field | Type | Required | Purpose |
| --- | --- | --- | --- |
| `feed` | scalar **or** `{ name, service-connection }` | optional | Enables the binary mirror. A bare string is shorthand for `{ name: <string> }`. |
| `registry` | scalar **or** `{ name, service-connection }` | optional | Enables the image mirror. |
| `service-connection` | string | optional | Shared fallback connection for whichever target omits its own. |

`feed` and `registry` are **independent** — set either, both, or neither.

## Authentication

Authentication is **asymmetric**.

### Feed (binaries)

Uses `NuGetAuthenticate@1` + `DownloadPackage@1`. The effective connection
resolves as: the feed's own `service-connection` → the top-level
`service-connection` → `$(System.AccessToken)`.

For a **same-organization** feed no service connection is required: grant the
pipeline's build identity the **Feed Reader** role and `NuGetAuthenticate@1`
authenticates automatically via `$(System.AccessToken)`. Set a
`service-connection` only for cross-org or external feeds.

### Registry (images)

Uses `az acr login` (`AzureCLI@2`) then `docker pull`.
`$(System.AccessToken)` **cannot** authenticate to a container registry, so a
service connection **must** resolve when `registry` is set — otherwise
compilation fails:

```
supply-chain.registry requires a service connection: set
`registry.service-connection` or a top-level `supply-chain.service-connection`.
A container registry (ACR) cannot be accessed with $(System.AccessToken).
```

## What the mirror must contain

Versions stay **pinned by the generating compiler**; the mirror must host the
exact pinned versions. Use the matching `ado-aw` compiler version against a
mirror that is a few days behind.

NuGet packages (same base names, **bare semver** versions, no leading `v`):

| Package id | Version | Must contain |
| --- | --- | --- |
| `ado-aw` | compiler version | `ado-aw-linux-x64`, `checksums.txt` |
| `awf` | AWF version | `awf-linux-x64`, `checksums.txt` |
| `ado-script` | compiler version | `ado-script.zip`, `checksums.txt` |

Container images. `registry.name` is a host **or base path** — the original
GHCR `github/...` prefix is **not** preserved; only the artifact name is kept,
directly under the base path at the same tag:

| GHCR source | Internal reference |
| --- | --- |
| `ghcr.io/github/gh-aw-firewall/squid:<awf-version>` | `<registry>/squid:<awf-version>` |
| `ghcr.io/github/gh-aw-firewall/agent:<awf-version>` | `<registry>/agent:<awf-version>` |
| `ghcr.io/github/gh-aw-mcpg:v<mcpg-version>` | `<registry>/gh-aw-mcpg:v<mcpg-version>` |

`<registry>` may be a bare host (`myacr.azurecr.io`) or a host with a namespace
path (`myacr.azurecr.io/oss-mirror`). The contract is only that the artifact
names (`squid`, `agent`, `gh-aw-mcpg`) and tags stay unchanged under it.

`sha256sum -c checksums.txt` verification is preserved on the internal branch,
so the mirror must ship the matching `checksums.txt`.

## Network isolation note

The mirror fetches run as ordinary ADO steps on the build agent — **outside**
the AWF network-isolation sandbox, which wraps only the copilot agent command.
The feed/registry hosts are therefore **not** added to the agent's AWF
allowlist. Isolating the build agent from GitHub / GHCR is enforced by the
agent pool's own network policy; the `supply-chain:` rerouting is what lets such
a locked-down pool succeed.
Loading
Loading