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
47 changes: 47 additions & 0 deletions docs/src/content/docs/reference/github-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,53 @@ permissions:

Alternatively, you can authenticate with a PAT or GitHub App. If using a GitHub App, add `vulnerability-alerts: read` to your workflow's `permissions:` field and ensure the GitHub App is configured with this permission.

## Cross-Visibility Opt-Out (`private-to-public-flows`)

By default, the MCP Gateway enforces _cross-visibility protections_ that prevent private repository data from flowing into public-repository sinks. These protections are active whenever the workflow runs in a public repository:

- **`forcePublicRepos`** — restricts the GitHub MCP server to public repositories only at runtime, preventing private-data secrecy tags from accumulating in the agent's context.
- **`sink-visibility` enforcement** — blocks any output to a sink whose visibility is `public` when the agent carries non-empty secrecy tags from private-repo reads.

When you intentionally need private-to-public data flows, declare `private-to-public-flows` under `tools.github`.

### Blanket opt-out (`allow`)

```yaml
tools:
github:
private-to-public-flows: allow
Comment on lines +185 to +192
```

This disables both `forcePublicRepos` and the default `sink-visibility` enforcement for **all** MCP servers. The MCP Gateway emits `"forcePublicRepos": false` in its startup config.

:::caution
`private-to-public-flows: allow` is **not compatible with strict mode**. Strict mode workflows that require this opt-out must use the list form instead.
:::

### Selective exemption (list of server IDs)

```yaml
tools:
github:
private-to-public-flows:
- github
- my-custom-server
mcp-servers:
my-custom-server:
type: http
url: "http://localhost:9000/mcp"
```
Comment on lines +205 to +213

This exempts only the listed MCP server IDs from the default `sink-visibility` enforcement. `forcePublicRepos` is **not** disabled; private repo access still requires the allow-only policy to permit it. This form is compatible with strict mode.

The compiler emits `"sinkVisibilityExemptServers": ["github", "my-custom-server"]` in the gateway config. The built-in GitHub MCP server ID is `github`. Custom server IDs match the key used in `mcp-servers`.

### Security implications

Opting out of cross-visibility protections means the agent may read from private repositories and write that data to public sinks (e.g., a public GitHub issue, a Slack channel). Only use this when your workflow explicitly requires it and you understand the data-flow implications.

See [MCP Gateway Specification Section 10.9](/gh-aw/reference/mcp-gateway/#109-cross-visibility-opt-out-private-to-public-flows) for full protocol details.

## Related Documentation

- [Tools Reference](/gh-aw/reference/tools/) - All tool configurations
Expand Down
26 changes: 14 additions & 12 deletions docs/src/content/docs/reference/mcp-gateway.md
Original file line number Diff line number Diff line change
Expand Up @@ -1647,43 +1647,45 @@ As a defense-in-depth measure, the gateway forces `sink-visibility="public"` for

### 10.9 Cross-Visibility Opt-Out (`private-to-public-flows`)

Workflow authors who intentionally allow private→public data flows can opt out of cross-visibility protections by declaring `private-to-public-flows` in workflow frontmatter. It accepts either `allow` for a blanket opt-out that disables both `forcePublicRepos` and sink-visibility enforcement, or a list of server IDs to exempt only those servers from default sink-visibility enforcement.
Workflow authors who intentionally allow private→public data flows can opt out of cross-visibility protections by declaring `private-to-public-flows` under `tools.github` in workflow frontmatter. It accepts either `allow` for a blanket opt-out that disables both `forcePublicRepos` and sink-visibility enforcement, or a list of server IDs to exempt only those servers from default sink-visibility enforcement.

#### 10.9.1 Workflow Frontmatter

**Blanket opt-out:**
```yaml
---
tools:
- github
- safe-outputs
private-to-public-flows: allow
github:
private-to-public-flows: allow
---
```

**Targeted opt-out (list form):**
```yaml
---
tools:
- github
- safe-outputs
- playwright
private-to-public-flows:
- playwright
github:
private-to-public-flows:
- github
- my-custom-server
mcp-servers:
my-custom-server:
type: http
url: "http://localhost:9000/mcp"
---
```

#### 10.9.2 Constraints

Blanket `allow` is incompatible with `guards_mode: strict`, so the compiler MUST reject that combination at compile time. The list form remains compatible with `strict` because it relaxes only the default sink-visibility for named servers while leaving other protections in place. In list form, every server ID MUST map to an actual MCP server declared in the workflow's `tools` list; unknown IDs MUST be rejected at compile time. With non-strict mode (`filter` or `propagate`), the blanket form disables both the forced `repos="public"` override (Section 4.1.3.8) and the `sink-visibility` runtime-verification override (Section 10.8.4).
Blanket `allow` is incompatible with `guards_mode: strict`, so the compiler MUST reject that combination at compile time. The list form remains compatible with `strict` because it relaxes only the default sink-visibility for named servers while leaving other protections in place. In list form, every server ID MUST map to an actual MCP server declared in the workflow's `tools` or `mcp-servers` list; unknown IDs MUST be rejected at compile time. With non-strict mode (`filter` or `propagate`), the blanket form disables both the forced `repos="public"` override (Section 4.1.3.8) and the `sink-visibility` runtime-verification override (Section 10.8.4).

#### 10.9.3 Compiler Responsibilities

When the compiler encounters `private-to-public-flows`, it MUST validate the chosen form, emit the matching gateway configuration, and record the opt-out in the audit trail.

For blanket `allow`, the compiler MUST reject `guards_mode: strict`, set `gateway.forcePublicRepos: false` in the generated JSON stdin config, and skip setting `sink-visibility: "public"` even if the target repo is public at compile time.
For blanket `allow`, the compiler MUST reject `guards_mode: strict`, set `gateway.forcePublicRepos: false` in the generated JSON stdin config, and skip setting `sink-visibility` in write-sink guard policies even if the target repo is public at compile time.

For list form, the compiler MUST verify that every listed server ID exists in the workflow's declared `tools` list, set `gateway.sinkVisibilityExemptServers` to that list in the generated JSON stdin config, and leave `forcePublicRepos` unchanged.
For list form, the compiler MUST verify that every listed server ID exists in the workflow's declared `tools` or `mcp-servers` list, set `gateway.sinkVisibilityExemptServers` to that list in the generated JSON stdin config, and leave `forcePublicRepos` unchanged.

#### 10.9.4 Interaction Matrix

Expand Down
Loading
Loading