githubnext / githubnext/ado-aw

Proxy Stage 1 Azure DevOps reads without exposing SC_READ_TOKEN

Open
#1,652 0 comments 0 reactions 0 assignees View on GitHub
agentic-workflows enhancement high-risk security
Dominant language
Rust
Stars
23
Forks
8
Avg merge
4d 9h
Merged PRs (30d)
22

Description

## Problem

`permissions.read` currently mints `SC_READ_TOKEN` from the configured ARM service connection and maps it into the Stage 1 Agent step as:

```yaml
env:
AZURE_DEVOPS_EXT_PAT: $(SC_READ_TOKEN)
```

This restores the documented ado-aw contract, but it also means the raw read-scoped ADO credential is visible inside the AWF sandbox. A prompt-injected agent with bash access can inspect or exfiltrate that token within the permitted network boundary.

The preferred long-term posture is the model used by gh-aw for `tools.github.mode: gh-proxy`: keep the real credential outside the agent container, expose a pre-authenticated CLI/HTTP path, and enforce read policy at a trusted proxy boundary.

## Historical context

- PR #286 / commit `f90bd81c` removed `AZURE_DEVOPS_EXT_PAT: $(SC_READ_TOKEN)` from Stage 1 on 2026-04-22, stating that ADO auth was handled by MCPG.
- PR #873 / commit `ca4a04b1` added the always-on Azure CLI and documented that `az devops` was automatically authenticated by `permissions.read`, but did not restore the direct Agent mapping.
- The Azure CLI smoke was fail-open: build `626382` logged an authentication error from `az devops project list`, then still emitted `noop`, so the child and candidate orchestrator passed.
- The regression was exposed after switching the smoke fixtures to Sonnet. Build `626456` explicitly reported that `AZURE_DEVOPS_EXT_PAT` was absent from the sandbox.
- PR #1508 currently restores the documented mapping as an immediate compatibility fix and adds deterministic compiled-output checks plus a fail-closed Azure CLI smoke.

## Reference architecture: gh-aw `gh-proxy`

Relevant gh-aw implementation:

- [`pkg/workflow/awf_helpers.go`](https://github.com/github/gh-aw/blob/main/pkg/workflow/awf_helpers.go)
- [`actions/setup/sh/start_cli_proxy.sh`](https://github.com/github/gh-aw/blob/main/actions/setup/sh/start_cli_proxy.sh)
- [`pkg/workflow/compiler_difc_proxy.go`](https://github.com/github/gh-aw/blob/main/pkg/workflow/compiler_difc_proxy.go)
- [`docs/src/content/docs/reference/github-tools.md`](https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/github-tools.md)

The important properties are:

1. The real `GH_TOKEN` is supplied to a host/trusted proxy, not the agent.
2. AWF uses `--exclude-env GH_TOKEN`, preventing the raw token from reaching the agent container.
3. The agent receives a pre-authenticated `gh` CLI path.
4. Requests are routed through a policy-aware proxy that injects authentication and applies repository/integrity guards.
5. Writes remain isolated behind safe outputs.

## Proposed ado-aw direction

Introduce a trusted Azure DevOps CLI/REST proxy for Stage 1 reads.

### Token flow

1. `permissions.read` continues to mint `SC_READ_TOKEN` outside AWF via `AzureCLI@2`.
2. The real token is passed only to a trusted proxy container/process.
3. The Agent step does **not** receive `SC_READ_TOKEN`, `AZURE_DEVOPS_EXT_PAT`, `SYSTEM_ACCESSTOKEN`, or `SC_WRITE_TOKEN`.
4. AWF explicitly excludes all ADO credential names from the agent container as defense in depth.
5. Inside the sandbox, `az devops` receives a non-secret sentinel credential if needed to bypass client-side login checks; the proxy strips that header and injects the real bearer upstream.

### Request routing

- Attach the proxy as a trusted AWF topology endpoint, analogous to MCPG/gh-aw's CLI proxy.
- Route Azure DevOps API traffic from `az devops`, `curl`, and SDK clients through the proxy.
- Prevent direct Stage 1 egress to ADO API hosts when proxy mode is active, otherwise an agent could bypass policy enforcement.
- Maintain an explicit upstream host allowlist (`dev.azure.com`, `vssps.dev.azure.com`, and any additional ADO hosts proven necessary).

### Read policy

A method-only policy is insufficient because Azure DevOps has read-like `POST` endpoints such as WIQL and batch-query APIs. The proxy needs a route-aware allowlist that classifies allowed read operations by normalized method + route.

Policy requirements:

- Fail closed for unknown routes, methods, API versions, or hosts.
- Permit only documented read operations required by supported Stage 1 tooling.
- Reject every mutating operation before forwarding.
- Normalize organization/project/resource path segments before matching.
- Bound request/response sizes and timeouts.
- Never log authorization headers, tokens, or unsanitized sensitive payloads.

The backing service connection should still be provisioned read-only. Proxy policy and identity permissions provide defense in depth; neither should be the sole control.

## Existing related surface

The Azure DevOps MCP already keeps `ADO_MCP_AUTH_TOKEN` in the MCPG child rather than the Agent process. This issue concerns the broader direct CLI/REST surface (`az devops`, `curl`, language SDKs) that currently requires `AZURE_DEVOPS_EXT_PAT` in Stage 1.

## Feasibility questions

1. Can AWF's existing `cli-proxy` sidecar be generalized for Azure DevOps, or should ado-aw ship a dedicated proxy through ado-script/MCPG?
2. Can `az devops` reliably use `HTTPS_PROXY` plus a sentinel `AZURE_DEVOPS_EXT_PAT`, including TLS CA injection inside the AWF container?
3. Which ADO hosts and redirects are required for Azure DevOps CLI read operations?
4. What is the minimum route catalog for repositories, builds, work items, identities, and search?
5. How should cross-project/cross-organization reads be represented and constrained?
6. Should proxy mode become automatic for every `permissions.read`, or begin as an opt-in migration mode?
7. How do we version the route policy so newly introduced Azure DevOps endpoints fail visibly rather than silently broadening access?

## Acceptance criteria

- [ ] A workflow with `permissions.read` can run `az devops project list` and supported read-only REST calls inside AWF without the real ADO token being present in the agent environment, files, argv, `/proc`, or logs.
- [ ] `SC_READ_TOKEN`, `SC_WRITE_TOKEN`, `SYSTEM_ACCESSTOKEN`, and the real `AZURE_DEVOPS_EXT_PAT` are absent from Agent and Detection containers.
- [ ] Detection receives no ADO access path or credential.
- [ ] Direct Stage 1 ADO API egress cannot bypass the proxy.
- [ ] Supported reads succeed through a route-aware allowlist.
- [ ] Representative writes through `az devops`, raw HTTP, and SDK clients are rejected by the proxy and produce no ADO mutation.
- [ ] Unknown routes/methods fail closed with actionable diagnostics.
- [ ] Proxy logs are auditable and sanitized.
- [ ] Standalone, 1ES, job, and stage targets emit the same credential boundary.
- [ ] Deterministic compiler tests assert token exclusion, proxy wiring, and Detection isolation.
- [ ] A live AgentPlayground smoke proves authenticated reads and deliberate write rejection without relying solely on model interpretation.
- [ ] Documentation explains the proxy trust boundary, route policy, service-connection requirements, and migration behavior.

## Non-goals

- Replacing Stage 3 safe-output authorization.
- Giving the Agent any write-capable ADO identity.
- Proxying general Azure Resource Manager or Microsoft Graph operations.
- Treating a single denied no-op write as proof that an identity is globally read-only.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reading gh-aw's pkg/workflow/awf_helpers.go, pkg/workflow/compiler_difc_proxy.go, actions/setup/sh/start_cli_proxy.sh, and the referenced GitHub tools documentation. Trace how permissions.read, the Stage 1 Agent, and the existing AWF cli-proxy are wired before deciding whether Azure DevOps can use that topology. Done means the acceptance criteria pass, including credential exclusion, fail-closed route policy, blocked writes, compiler checks, and the live AgentPlayground smoke.

Written by the indexing model from the issue text.

Assessment

Tech stack
azure, cli, rust
Domain
api, cli, devops, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.