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
7 changes: 4 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ The system is orchestrated by `src/cli.ts` and managed by `src/docker-manager.ts
**4. Unified Enclaves (optional)** — `containers/enclave/`
- Enabled by declaring `enclaves` entries in the AWF config file
- One AWF-owned MCP server (`enclave-mcp-server`) exposes enabled enclave executors only through compiler-launched `gh-aw-mcpg`; the primary agent gets no direct enclave socket, wrapper binary, capability, or private transport
- `enclave_run_script` launches a no-network, read-only, single-use Python executor and returns one canonical JSON result
- `enclave_run_agent` launches a single-use Copilot enclave on the dedicated `internal` `awf-enclave-agent` network whose sole peer is the dedicated API proxy; Squid, the primary agent, the general API proxy, safe outputs, and the MCP gateway are excluded
- `enclave_run_script` launches a no-network, read-only, single-use Python enclave and returns one canonical JSON result
- `enclave_run_agent` launches a single-use Copilot enclave on the dedicated `internal` `awf-enclave-agent` network. Its mandatory peer is the dedicated API proxy; when GitHub access is configured (static `agent.tools.github` / legacy `issues-read-v1`, or a dynamic entry), compiler-owned shared mcpg is also attached at `172.31.0.40` under alias `awf-enclave-github-mcp`. Squid, the primary agent, the general API proxy, safe outputs, and `enclave-mcp-server` itself are excluded, and AWF asserts the exact membership set before launch
- Script and agent executors are configured as a top-level `enclaves` array of `script`/`agent` entries whose merged `repos` lists form one trusted repository catalog, sharing one per-run information ledger and one AWF-owned admission lane
- Rollout depends on the compiler handoff contract in `github/gh-aw#50920` and late backend rediscovery in `github/gh-aw-mcpg#10784`, which requires MCP Gateway spec 1.15.0 and the first mcpg release after v0.4.8 containing it
- **Dynamic repository enclaves** additionally admit repositories at runtime through mcpg's `github-repository-delegation-v1` controller. AWF's control client runs in the **host process** (the control endpoint is published to host loopback only) and `enclave-mcp-server` reaches it over a `0700` AWF-private file channel, not a network. That control listener is guarded by capability authentication alone — see `github/gh-aw#59268`, closed as not planned
- Rollout depends on the compiler handoff contract in `github/gh-aw#50920` and late backend rediscovery in `github/gh-aw-mcpg#10784`, which requires MCP Gateway spec 1.15.0 and the first mcpg release after v0.4.8 containing it. That floor covers static entries; **dynamic repository admission requires mcpg v0.4.18 or newer**, whose `internal/delegation/wire.go` encodes delegation durations as whole seconds (v0.4.17 read the same fields as `time.Duration` nanoseconds)
- While the gateway backend is still coming up, AWF retries retryable HTTP `503 backend_unavailable` responses within `AWF_ENCLAVE_MCP_READINESS_TIMEOUT_MS`
- See [docs/enclaves-architecture.md](docs/enclaves-architecture.md) and [docs/awf-config-spec.md](docs/awf-config-spec.md) §14

Expand Down
4 changes: 3 additions & 1 deletion docs/awf-config-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -2033,7 +2033,9 @@ server itself remain excluded.
The base compiler handoff from `github/gh-aw#50920` and late backend
rediscovery from `github/gh-aw-mcpg#10784` are present in mcpg v0.4.15, which
reports MCP Gateway spec 1.16.0. The base floor remains spec 1.15.0 and a
post-v0.4.8 mcpg release.
post-v0.4.8 mcpg release. That floor covers static entries only; dynamic
repository admission requires mcpg v0.4.18 or newer for the whole-second
delegation duration encoding (see §14 and `docs/enclaves-architecture.md`).

GitHub access additionally requires compiler support for mcpg multi-agent
identities and policies, tracked by `github/gh-aw#57787`. The compiler MUST gate
Expand Down
22 changes: 20 additions & 2 deletions docs/enclaves-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@ Layer 5 establishes one `enclaves` subsystem, one AWF-owned MCP server, and mcpg

Dynamic repository admission described below is implemented and version-gated.
It runs only when the gh-aw compiler starts mcpg's
`github-repository-delegation-v1` controller (mcpg v0.4.17 or newer) and hands
`github-repository-delegation-v1` controller (mcpg v0.4.18 or newer) and hands
AWF its loopback-only control endpoint and AWF-only control capability; every
other combination fails closed before execution. Static entries continue to
declare a non-empty `repos` list and use immutable seeds.

v0.4.18 is the floor, not v0.4.17, because the delegation duration fields are
whole seconds on the wire. v0.4.17 declared `max_identity_ttl` and
`requested_ttl` as Go `time.Duration` and so decoded them as **nanoseconds**;
v0.4.18 added `internal/delegation/wire.go`, which decodes both as `int64`
seconds. Pairing current AWF with v0.4.17 would silently reinterpret a
120-second TTL as 120 nanoseconds. gh-aw pins the matching default in
`pkg/constants/version_constants.go` (`DefaultMCPGatewayVersion`).

## Architecture

AWF stages immutable repository seeds on the host, starts one AWF-owned `enclave-mcp-server`, and exposes enabled executors only through `gh-aw-mcpg`.
Expand Down Expand Up @@ -101,7 +109,9 @@ error immediately instead of entering an unbounded fixed-timing queue.

The base MCP handoff and late backend rediscovery are present in mcpg v0.4.15,
which reports MCP Gateway spec 1.16.0. The earlier minimum remains spec 1.15.0
and a post-v0.4.8 mcpg release.
and a post-v0.4.8 mcpg release. That minimum applies to static entries only;
dynamic repository admission requires v0.4.18 or newer, as described under
Status above.

The optional GitHub path additionally requires compiler support for mcpg
multi-agent identities and policies (tracked by `github/gh-aw#57787`). The
Expand Down Expand Up @@ -408,6 +418,14 @@ plane is therefore protected by **authentication**: every request must carry the
AWF-only capability, which is never placed in any container's environment or
mount, and mcpg rejects anything else with `403 delegation_access_denied`.

Relying on authentication alone here is a deliberate, reviewed choice rather
than an oversight: `github/gh-aw#59268` proposed adding a topological control
and was closed as not planned, with the reasoning recorded on the issue. mcpg
verifies the capability in constant time against a stored SHA-256 digest,
before any control routing, on a handler separate from the executor-facing data
plane — so holding a valid executor bearer does not reach control operations
even from a co-attached network.

The broker asks the host for admission over an AWF-private request/response
directory inside the `0700` enclave private root that is bind-mounted only into
the broker:
Expand Down
9 changes: 7 additions & 2 deletions src/enclave/delegation-control-client.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/**
* Strict client for mcpg v0.4.17's `github-repository-delegation-v1` control
* Strict client for mcpg v0.4.18's `github-repository-delegation-v1` control
* channel (`github/gh-aw-mcpg` `internal/proxy/delegation.go`,
* `internal/delegation/{identity,store,envelope}.go`).
* `internal/delegation/{identity,store,envelope,wire}.go`).
*
* v0.4.18 is the minimum: it introduced `internal/delegation/wire.go`, which
* decodes `requested_ttl` and `max_identity_ttl` as `int64` whole seconds.
* v0.4.17 typed them as Go `time.Duration` and so read the same JSON as
* nanoseconds.
*
* Wire contract, reproduced exactly because mcpg decodes with
* `DisallowUnknownFields` and rejects anything outside it:
Expand Down
8 changes: 5 additions & 3 deletions src/enclave/dynamic-delegation-contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
* `pkg/workflow/enclaves.go` (PR #59046): the exported control endpoint,
* the fixed control API base path, the controller name, the envelope's
* `run_id` and `enclave_backend`.
* - `github/gh-aw-mcpg` v0.4.17 `internal/proxy/delegation.go` and
* - `github/gh-aw-mcpg` v0.4.18 `internal/proxy/delegation.go`,
* `internal/delegation/wire.go`, and
* `internal/delegation/{identity,store,selector}.go` (PR #12605): the
* operation paths, the `CreateOrConfirmRequest`/`IdentityResult` JSON key
* sets, the status/reconcile/revoke shapes, and the closed tool set.
* sets, the whole-second duration encoding, the status/reconcile/revoke
* shapes, and the closed tool set.
*/

import * as http from 'http';
Expand Down Expand Up @@ -98,7 +100,7 @@ describe('gh-aw handoff contract', () => {
});
});

describe('mcpg v0.4.17 wire contract', () => {
describe('mcpg v0.4.18 wire contract', () => {
const captured: Record<string, unknown>[] = [];
let server: http.Server;
let client: DelegationControlClient;
Expand Down
2 changes: 1 addition & 1 deletion src/enclave/dynamic-delegation-handoff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export const ENCLAVE_GITHUB_DELEGATION_CONTROL_CAPABILITY_ENV =
'AWF_ENCLAVE_GITHUB_DELEGATION_CONTROL_CAPABILITY';

/**
* Fixed control API base path served by mcpg v0.4.17
* Fixed control API base path served by mcpg v0.4.18
* (`internal/proxy/delegation.go`: `delegationControlPath`). Operations are
* siblings of the controller name, not children of it.
*/
Expand Down
Loading