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
31 changes: 14 additions & 17 deletions docs/src/content/docs/guides/maintaining-repos.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Review the newly opened issue. Based on the issue content:
5. Otherwise, post a comment thanking the contributor and explaining what information is still needed.
```

`min-integrity: unapproved` allows repo-assist to see all community content — first-time contributors, external users, everyone. The `safe-outputs` block limits what repo-assist can do in response: it can only apply labels and post comments. Any other GitHub mutation (opening PRs, merging, closing issues) is blocked by the runtime, regardless of what the agent attempts.
`min-integrity: unapproved` allows repo-assist to see content from contributors who have previously interacted with the repository — including first-time contributors and users who have had PRs merged before — while still filtering out content from brand-new GitHub users (`FIRST_TIMER`) and users with no repository association (`NONE`). For most active repositories, this captures the vast majority of community input. The `safe-outputs` block limits what repo-assist can do in response: it can only apply labels and post comments. Any other GitHub mutation (opening PRs, merging, closing issues) is blocked by the runtime, regardless of what the agent attempts.

### Routing to Downstream Agents

Expand Down Expand Up @@ -134,7 +134,7 @@ When a safe-output validation failure appears in your audit logs, it means the a

## Controlling Workflow Inputs with Integrity Filtering

Integrity filtering is the primary mechanism for controlling what content the agent sees. It evaluates the author of each issue, PR, or comment and removes items that don't meet the configured trust threshold — before the agent's context is assembled. Every public repository automatically applies `min-integrity: approved` as a baseline — repo-assist overrides this to `unapproved` so it can see all incoming issues.
Integrity filtering is the primary mechanism for controlling what content the agent sees. It evaluates the author of each issue, PR, or comment and removes items that don't meet the configured trust threshold — before the agent's context is assembled. Every public repository automatically applies `min-integrity: approved` as a baseline — repo-assist overrides this to `unapproved` so it can see issues from contributors and first-time contributors, not just trusted members.

The four configurable levels, from most to least restrictive:

Expand All @@ -147,7 +147,7 @@ The four configurable levels, from most to least restrictive:

Choose based on what the workflow does:

- **Repo-assist / triage workflows**: `unapproved` — classify all community content without acting on it.
- **Repo-assist / triage workflows**: `unapproved` — classify content from contributors and first-time contributors without acting on it.
- **Code-modifying workflows** (open PRs, apply patches, close issues): `approved` or `merged` — only act on trusted input.
- **Spam detection or analytics**: `none` — see everything, but produce no direct GitHub mutations.

Expand Down Expand Up @@ -202,30 +202,27 @@ The runtime automatically merges per-workflow values with the variable. Set thes

### Reactions as Trust Signals

Starting from MCPG v0.2.18, maintainers can use GitHub reactions (👍, ❤️) to promote content past the integrity filter without modifying labels. This is useful in repo-assist workflows where a maintainer wants to fast-track an external contribution:
Starting from gh-aw v0.68.2, maintainers can use GitHub reactions (👍, ❤️) to promote content past the integrity filter without modifying labels. This is useful in repo-assist workflows where a maintainer wants to fast-track an external contribution.

To enable reactions, add the `integrity-reactions` feature flag:

```aw wrap
features:
integrity-reactions: true
mcp-gateway:
version: "v0.2.18"
tools:
github:
min-integrity: approved
endorsement-reactions:
- "THUMBS_UP"
- "HEART"
disapproval-reactions:
- "THUMBS_DOWN"
- "CONFUSED"
endorser-min-integrity: approved
disapproval-integrity: none
```

When a trusted member (at or above `endorser-min-integrity`) adds an endorsement reaction to an issue or comment, the item's integrity is promoted to `approved`. A disapproval reaction demotes it to the level set by `disapproval-integrity`.
The compiler handles the rest — when `integrity-reactions: true` is set, it automatically:

- Enables the CLI proxy (`cli-proxy: true`), which is required for reaction-based integrity decisions
- Injects default endorsement reactions: `THUMBS_UP`, `HEART`
- Injects default disapproval reactions: `THUMBS_DOWN`, `CONFUSED`
- Uses `endorser-min-integrity: approved` (only reactions from owners, members, and collaborators count)
- Uses `disapproval-integrity: none` (a disapproval reaction demotes content to `none`)

> [!IMPORTANT]
> Reactions only work when running through the MCPG proxy mode. They are not available in gateway mode.
These defaults mean that when a trusted member (owner, member, or collaborator) adds a 👍 or ❤️ reaction to an issue or comment, the item's integrity is promoted to `approved` — making it visible to agents using `min-integrity: approved`. Conversely, a 👎 or 😕 reaction from a trusted member demotes the item to `none`.

See the [Integrity Filtering Reference](/gh-aw/reference/integrity/) for complete configuration details.

Expand Down
13 changes: 11 additions & 2 deletions pkg/workflow/compiler_difc_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,13 +334,22 @@ func (c *Compiler) generateStopDIFCProxyStep(yaml *strings.Builder, data *Workfl
// isCliProxyNeeded returns true if the CLI proxy should be started on the host.
//
// The CLI proxy is needed when:
// 1. The cli-proxy feature flag is enabled, and
// 1. The cli-proxy feature flag is enabled (explicitly or implicitly), and
// 2. The AWF sandbox (firewall) is enabled, and
// 3. The AWF version supports CLI proxy flags
//
// The cli-proxy feature is implicitly enabled when integrity-reactions is enabled,
// because reaction-based integrity decisions require the proxy to identify reaction authors.
func isCliProxyNeeded(data *WorkflowData) bool {
if !isFeatureEnabled(constants.CliProxyFeatureFlag, data) {
cliProxyEnabled := isFeatureEnabled(constants.CliProxyFeatureFlag, data)
integrityReactionsEnabled := isFeatureEnabled(constants.IntegrityReactionsFeatureFlag, data)

if !cliProxyEnabled && !integrityReactionsEnabled {
return false
}
if integrityReactionsEnabled && !cliProxyEnabled {
difcProxyLog.Print("integrity-reactions enabled: implicitly enabling CLI proxy")
}
if !isFirewallEnabled(data) {
return false
}
Expand Down
100 changes: 100 additions & 0 deletions pkg/workflow/compiler_difc_proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -810,3 +810,103 @@ func TestResolveProxyContainerImage(t *testing.T) {
})
}
}

// TestIsCliProxyNeeded_IntegrityReactionsImplicitEnable verifies that the CLI proxy
// is implicitly enabled when the integrity-reactions feature flag is set, even without
// an explicit cli-proxy feature flag.
func TestIsCliProxyNeeded_IntegrityReactionsImplicitEnable(t *testing.T) {
awfVersion := "0.25.20"

tests := []struct {
name string
Comment on lines +817 to +821
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test calls isFeatureEnabled via isCliProxyNeeded, which can read GH_AW_FEATURES from the environment. To keep the test hermetic (and avoid failures when GH_AW_FEATURES is set in a developer’s shell/CI), explicitly clear or set GH_AW_FEATURES (e.g., t.Setenv("GH_AW_FEATURES", "")) at the start of the test.

Copilot uses AI. Check for mistakes.
data *WorkflowData
expected bool
desc string
}{
{
name: "integrity-reactions enables cli proxy implicitly",
data: &WorkflowData{
NetworkPermissions: &NetworkPermissions{
Firewall: &FirewallConfig{
Enabled: true,
Version: awfVersion,
},
},
Features: map[string]any{"integrity-reactions": true},
},
expected: true,
desc: "integrity-reactions should implicitly enable the CLI proxy",
},
{
name: "explicit cli-proxy still works",
data: &WorkflowData{
NetworkPermissions: &NetworkPermissions{
Firewall: &FirewallConfig{
Enabled: true,
Version: awfVersion,
},
},
Features: map[string]any{"cli-proxy": true},
},
expected: true,
desc: "explicit cli-proxy feature flag should still enable the CLI proxy",
},
{
name: "both flags enabled",
data: &WorkflowData{
NetworkPermissions: &NetworkPermissions{
Firewall: &FirewallConfig{
Enabled: true,
Version: awfVersion,
},
},
Features: map[string]any{"cli-proxy": true, "integrity-reactions": true},
},
expected: true,
desc: "both flags together should enable the CLI proxy",
},
{
name: "neither flag set",
data: &WorkflowData{
NetworkPermissions: &NetworkPermissions{
Firewall: &FirewallConfig{
Enabled: true,
Version: awfVersion,
},
},
Features: map[string]any{},
},
expected: false,
desc: "no feature flags should not enable the CLI proxy",
},
{
name: "integrity-reactions without firewall",
data: &WorkflowData{
Features: map[string]any{"integrity-reactions": true},
},
expected: false,
desc: "integrity-reactions without firewall should not enable the CLI proxy",
},
{
name: "integrity-reactions with old AWF version",
data: &WorkflowData{
NetworkPermissions: &NetworkPermissions{
Firewall: &FirewallConfig{
Enabled: true,
Version: "v0.25.16",
},
},
Features: map[string]any{"integrity-reactions": true},
},
expected: false,
desc: "integrity-reactions with old AWF version should not enable the CLI proxy",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := isCliProxyNeeded(tt.data)
assert.Equal(t, tt.expected, got, tt.desc)
})
}
}
7 changes: 5 additions & 2 deletions pkg/workflow/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,13 @@ func collectDockerImages(tools map[string]any, workflowData *WorkflowData, actio
}
}

// Add cli-proxy sidecar container when the cli-proxy feature flag is enabled
// Add cli-proxy sidecar container when the cli-proxy is needed (explicitly via
// cli-proxy feature flag, or implicitly via integrity-reactions feature flag)
// and the AWF version supports it. Without this, --skip-pull causes AWF to fail
// because the cli-proxy image was never pulled.
if isFeatureEnabled(constants.CliProxyFeatureFlag, workflowData) && awfSupportsCliProxy(firewallConfig) {
cliProxyNeeded := isFeatureEnabled(constants.CliProxyFeatureFlag, workflowData) ||
isFeatureEnabled(constants.IntegrityReactionsFeatureFlag, workflowData)
if cliProxyNeeded && awfSupportsCliProxy(firewallConfig) {
Comment on lines +106 to +112
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

collectDockerImages uses the same cli-proxy || integrity-reactions condition as isCliProxyNeeded, but other runtime wiring for cli-proxy is still gated solely on features.cli-proxy (AWF flags, env exclusions, etc.). Until those other call sites also treat integrity-reactions as enabling cli-proxy, this can lead to pulling the cli-proxy image even though the cli-proxy sidecar won't actually be started/used. Align the condition across the whole cli-proxy pipeline (ideally via a shared helper) so image pulling matches actual runtime usage.

Copilot uses AI. Check for mistakes.
cliProxyImage := constants.DefaultFirewallRegistry + "/cli-proxy:" + awfImageTag
if !imageSet[cliProxyImage] {
images = append(images, cliProxyImage)
Expand Down
Loading