From 9a874f6f75a6894de37cce9c230b02f660f1c5c8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 20 Mar 2026 23:23:06 +0000
Subject: [PATCH 1/4] docs: add integrity.md reference documentation

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/89ab451b-a195-4968-9e91-283883057c76
---
 .github/workflows/smoke-codex.lock.yml | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml
index 72012049156..2b9da5373fb 100644
--- a/.github/workflows/smoke-codex.lock.yml
+++ b/.github/workflows/smoke-codex.lock.yml
@@ -455,13 +455,20 @@ jobs:
               {
                 "description": "Add the 'smoked' label to the current pull request (can only be called once)",
                 "inputSchema": {
-                  "additionalProperties": true,
+                  "additionalProperties": false,
                   "properties": {
-                    "payload": {
-                      "description": "JSON-encoded payload to pass to the action",
+                    "labels": {
+                      "description": "The labels' name to be added. Must be separated with line breaks if there're multiple labels.",
+                      "type": "string"
+                    },
+                    "number": {
+                      "description": "The number of the issue or pull request.",
                       "type": "string"
                     }
                   },
+                  "required": [
+                    "labels"
+                  ],
                   "type": "object"
                 },
                 "name": "add_smoked_label"
@@ -1566,7 +1573,8 @@ jobs:
         env:
           GITHUB_TOKEN: ${{ github.token }}
         with:
-          payload: ${{ steps.process_safe_outputs.outputs.action_add_smoked_label_payload }}
+          labels: ${{ fromJSON(steps.process_safe_outputs.outputs.action_add_smoked_label_payload).labels }}
+          number: ${{ fromJSON(steps.process_safe_outputs.outputs.action_add_smoked_label_payload).number }}
       - name: Upload safe output items
         if: always()
         uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0

From 7fa5a695c3e4a86cc8dc6908fab587ba10e8661a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 20 Mar 2026 23:39:07 +0000
Subject: [PATCH 2/4] docs: add integrity.md reference documentation for
 integrity filtering

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/89ab451b-a195-4968-9e91-283883057c76
---
 docs/src/content/docs/reference/integrity.md | 168 +++++++++++++++++++
 1 file changed, 168 insertions(+)
 create mode 100644 docs/src/content/docs/reference/integrity.md

diff --git a/docs/src/content/docs/reference/integrity.md b/docs/src/content/docs/reference/integrity.md
new file mode 100644
index 00000000000..c3e19f059f3
--- /dev/null
+++ b/docs/src/content/docs/reference/integrity.md
@@ -0,0 +1,168 @@
+---
+title: Integrity Filtering
+description: How integrity filtering restricts agent access to GitHub content based on author trust and merge status, and how filtered events appear in logs.
+sidebar:
+  order: 680
+---
+
+Integrity filtering controls which GitHub content an agent can access during a workflow run. Rather than filtering by permissions, it filters by **trust**: the author association of an issue, pull request, or comment, and whether that content has been merged into the main branch.
+
+## How It Works
+
+The MCP gateway intercepts tool calls to GitHub and applies integrity checks to each piece of content returned. If an item's integrity level is below the configured minimum, the gateway discards it before the AI engine sees it. This happens transparently — the agent never receives filtered content, and filtered items are logged as `DIFC_FILTERED` events for later inspection.
+
+## Configuration
+
+Set `min-integrity` under `tools.github` in your workflow frontmatter:
+
+```aw wrap
+tools:
+  github:
+    min-integrity: approved
+```
+
+`min-integrity` can be specified alone. When `repos` is omitted, it defaults to `"all"`. If `repos` is also specified, both fields must be present.
+
+```aw wrap
+tools:
+  github:
+    repos: "myorg/*"
+    min-integrity: approved
+```
+
+## Integrity Levels
+
+| Level | What passes through |
+|-------|---------------------|
+| `merged` | Objects reachable from the main branch (any author) |
+| `approved` | Objects authored by `OWNER`, `MEMBER`, or `COLLABORATOR` |
+| `unapproved` | Objects authored by `CONTRIBUTOR` or `FIRST_TIME_CONTRIBUTOR` |
+| `none` | All objects, including `FIRST_TIMER` and users with no association (`NONE`) |
+
+Levels are ordered from most restrictive to least. Setting `min-integrity: approved` means only `approved` and `merged` content reaches the agent. `unapproved` and `none` content is filtered out.
+
+**`merged`** is the strictest level. An item qualifies as `merged` when it is reachable from the default branch, regardless of who authored it. This is useful for workflows that should only act on production content.
+
+**`approved`** corresponds to users who have a formal trust relationship with the repository: owners, members, and collaborators. This is the most common choice for public repository workflows.
+
+**`unapproved`** includes contributors who have had code merged before, as well as first-time contributors. Appropriate when community participation is welcome and the workflow's outputs are reviewed before being applied.
+
+**`none`** allows all content through. Use this deliberately, with appropriate safeguards, for workflows designed to process untrusted input — such as triage bots or spam detection.
+
+## Default Behavior
+
+For **public repositories**, if no `min-integrity` or `lockdown` is configured, the runtime automatically applies `min-integrity: approved`. This protects public workflows even when additional authentication has not been set up. See [Automatic Minimum-Integrity Protection](/gh-aw/reference/lockdown-mode/#automatic-minimum-integrity-protection) for details.
+
+For **private and internal repositories**, no guard policy is applied automatically. Content from all users is accessible by default.
+
+## Choosing a Level
+
+The right level depends on who you want the agent to see content from:
+
+- **Workflows that automate code review or apply changes**: `merged` or `approved` — only act on trusted content.
+- **Workflows that respond to maintainers and trusted contributors**: `approved` — a common, safe default for most workflows.
+- **Community triage or planning workflows**: `unapproved` — allow contributor input while excluding anonymous or first-time interactions.
+- **Public-data workflows or spam detection**: `none` — see all activity, but ensure the workflow's outputs are not directly applied without review.
+
+> [!WARNING]
+> Setting `min-integrity: none` on a public repository disables the automatic protection. Only use it when the workflow is explicitly designed to handle untrusted input.
+
+## Examples
+
+**Allow only merged content:**
+
+```aw wrap
+tools:
+  github:
+    repos: "all"
+    min-integrity: merged
+```
+
+**Trusted contributors only (typical for a public repository workflow):**
+
+```aw wrap
+tools:
+  github:
+    min-integrity: approved
+```
+
+**Allow all community contributions (for a triage workflow):**
+
+```aw wrap
+tools:
+  github:
+    min-integrity: unapproved
+```
+
+**Explicitly disable filtering on a public repository:**
+
+```aw wrap
+tools:
+  github:
+    min-integrity: none
+```
+
+**Scope to specific organizations with integrity filtering:**
+
+```aw wrap
+tools:
+  github:
+    mode: remote
+    toolsets: [repos, issues, pull_requests]
+    repos:
+      - "myorg/*"
+      - "partner/shared-repo"
+    min-integrity: approved
+```
+
+## In Logs and Reports
+
+When an item is filtered by the integrity check, the MCP gateway records a `DIFC_FILTERED` event in the run's `gateway.jsonl` log. Each event includes:
+
+- **Server**: the MCP server that returned the filtered content
+- **Tool**: the tool call that produced it (e.g., `list_issues`, `get_pull_request`)
+- **User**: the login of the content's author
+- **Reason**: a description such as `"Resource has lower integrity than agent requires."`
+- **Integrity tags**: the tags assigned to the item that caused it to be filtered
+- **Author association**: the GitHub author association (`CONTRIBUTOR`, `FIRST_TIMER`, etc.)
+
+When gateway metrics are displayed, filtered events appear in a **DIFC Filtered Events** table alongside the standard server usage table:
+
+```text
+┌─────────────────────────────────────────────────────────────────────────────────────┐
+│ DIFC Filtered Events                                                                │
+├────────────────┬───────────────┬───────────────┬─────────────────────────────────-─┤
+│ Server         │ Tool          │ User          │ Reason                             │
+├────────────────┼───────────────┼───────────────┼────────────────────────────────────┤
+│ github         │ list_issues   │ new-user      │ Resource has lower integrity than  │
+│                │               │               │ agent requires.                    │
+└────────────────┴───────────────┴───────────────┴────────────────────────────────────┘
+```
+
+The `Total DIFC Filtered` count in the summary line shows how many items were suppressed during the run.
+
+### Filtering Logs by Integrity Events
+
+To download only runs that had integrity-filtered content, use the `--filtered-integrity` flag with the `logs` command:
+
+```bash
+gh aw logs --filtered-integrity
+```
+
+This is useful when investigating whether your `min-integrity` configuration is filtering expected content or when tuning the level after observing real traffic patterns.
+
+## Relationship to Lockdown Mode
+
+[Lockdown Mode](/gh-aw/reference/lockdown-mode/) is a separate but related feature of the GitHub MCP server. It filters content to users with push access. The two features can coexist:
+
+- `lockdown: true` filters using the GitHub MCP server's own content filter (based on push access).
+- `min-integrity` filters using the MCP gateway's DIFC mechanism (based on author association and merge status).
+
+For most public repository workflows, `min-integrity: approved` provides equivalent protection to lockdown mode without requiring additional authentication.
+
+## Related Documentation
+
+- [GitHub Tools Reference](/gh-aw/reference/github-tools/) — Full `tools.github` configuration including `repos` and guard policies
+- [Lockdown Mode](/gh-aw/reference/lockdown-mode/) — GitHub MCP server content filtering for public repositories
+- [MCP Gateway](/gh-aw/reference/mcp-gateway/) — Gateway architecture and log format
+- [CLI Reference: logs](/gh-aw/setup/cli/#logs) — Downloading and analyzing workflow run logs

From 63d5bcba131e20d40133cc49689051328f34dd8c Mon Sep 17 00:00:00 2001
From: Landon Cox <landon.cox@microsoft.com>
Date: Fri, 20 Mar 2026 17:02:18 -0700
Subject: [PATCH 3/4] docs: add blocked-users, approval-labels, and accuracy
 improvements

- Add 'Adjusting Integrity Per-Item' section covering blocked-users,
  approval-labels, and effective integrity computation order
- Make integrity levels table more precise: mention private repo
  auto-elevation, trusted bots, non-fork PR treatment
- Rename table column to 'What qualifies at this level' and clarify
  cumulative behavior (approved allows approved AND merged)
- Clarify merged level: PRs qualify by merge state, commits by
  reachability from default branch
- Add two new examples: blocked-users and human-review gate
- Remove unrelated smoke-codex.lock.yml change
- Fix stray character in ASCII table

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
 .github/workflows/smoke-codex.lock.yml       |  16 +--
 docs/src/content/docs/reference/integrity.md | 100 ++++++++++++++++---
 2 files changed, 88 insertions(+), 28 deletions(-)

diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml
index 2b9da5373fb..72012049156 100644
--- a/.github/workflows/smoke-codex.lock.yml
+++ b/.github/workflows/smoke-codex.lock.yml
@@ -455,20 +455,13 @@ jobs:
               {
                 "description": "Add the 'smoked' label to the current pull request (can only be called once)",
                 "inputSchema": {
-                  "additionalProperties": false,
+                  "additionalProperties": true,
                   "properties": {
-                    "labels": {
-                      "description": "The labels' name to be added. Must be separated with line breaks if there're multiple labels.",
-                      "type": "string"
-                    },
-                    "number": {
-                      "description": "The number of the issue or pull request.",
+                    "payload": {
+                      "description": "JSON-encoded payload to pass to the action",
                       "type": "string"
                     }
                   },
-                  "required": [
-                    "labels"
-                  ],
                   "type": "object"
                 },
                 "name": "add_smoked_label"
@@ -1573,8 +1566,7 @@ jobs:
         env:
           GITHUB_TOKEN: ${{ github.token }}
         with:
-          labels: ${{ fromJSON(steps.process_safe_outputs.outputs.action_add_smoked_label_payload).labels }}
-          number: ${{ fromJSON(steps.process_safe_outputs.outputs.action_add_smoked_label_payload).number }}
+          payload: ${{ steps.process_safe_outputs.outputs.action_add_smoked_label_payload }}
       - name: Upload safe output items
         if: always()
         uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
diff --git a/docs/src/content/docs/reference/integrity.md b/docs/src/content/docs/reference/integrity.md
index c3e19f059f3..8e9e25d83c4 100644
--- a/docs/src/content/docs/reference/integrity.md
+++ b/docs/src/content/docs/reference/integrity.md
@@ -9,7 +9,7 @@ Integrity filtering controls which GitHub content an agent can access during a w
 
 ## How It Works
 
-The MCP gateway intercepts tool calls to GitHub and applies integrity checks to each piece of content returned. If an item's integrity level is below the configured minimum, the gateway discards it before the AI engine sees it. This happens transparently — the agent never receives filtered content, and filtered items are logged as `DIFC_FILTERED` events for later inspection.
+The MCP gateway intercepts tool calls to GitHub and applies integrity checks to each piece of content returned. If an item's integrity level is below the configured minimum, the gateway removes it before the AI engine sees it. This happens transparently — the agent receives a reduced result set, and filtered items are logged as `DIFC_FILTERED` events for later inspection.
 
 ## Configuration
 
@@ -32,23 +32,70 @@ tools:
 
 ## Integrity Levels
 
-| Level | What passes through |
-|-------|---------------------|
-| `merged` | Objects reachable from the main branch (any author) |
-| `approved` | Objects authored by `OWNER`, `MEMBER`, or `COLLABORATOR` |
+| Level | What qualifies at this level |
+|-------|------------------------------|
+| `merged` | Pull requests that have been merged, and commits reachable from the default branch (any author) |
+| `approved` | Objects authored by `OWNER`, `MEMBER`, or `COLLABORATOR`; non-fork PRs on public repos; all items in private repos; trusted platform bots (e.g., dependabot) |
 | `unapproved` | Objects authored by `CONTRIBUTOR` or `FIRST_TIME_CONTRIBUTOR` |
 | `none` | All objects, including `FIRST_TIMER` and users with no association (`NONE`) |
 
-Levels are ordered from most restrictive to least. Setting `min-integrity: approved` means only `approved` and `merged` content reaches the agent. `unapproved` and `none` content is filtered out.
+Levels are cumulative and ordered from most restrictive to least. Setting `min-integrity: approved` means only items at `approved` level **or higher** (`merged`) reach the agent. Items at `unapproved` or `none` are filtered out.
 
-**`merged`** is the strictest level. An item qualifies as `merged` when it is reachable from the default branch, regardless of who authored it. This is useful for workflows that should only act on production content.
+**`merged`** is the strictest level. A pull request qualifies as `merged` when it has been merged into the target branch. Commits qualify when they are reachable from the default branch. This is useful for workflows that should only act on production content.
 
-**`approved`** corresponds to users who have a formal trust relationship with the repository: owners, members, and collaborators. This is the most common choice for public repository workflows.
+**`approved`** corresponds to users who have a formal trust relationship with the repository: owners, members, and collaborators. Items in private repositories are automatically elevated to `approved` (since only collaborators can access them). Recognized platform bots such as dependabot and github-actions also receive `approved` integrity. This is the most common choice for public repository workflows.
 
 **`unapproved`** includes contributors who have had code merged before, as well as first-time contributors. Appropriate when community participation is welcome and the workflow's outputs are reviewed before being applied.
 
 **`none`** allows all content through. Use this deliberately, with appropriate safeguards, for workflows designed to process untrusted input — such as triage bots or spam detection.
 
+## Adjusting Integrity Per-Item
+
+Beyond setting a minimum level, you can override integrity for specific authors or labels.
+
+### Blocking specific users
+
+`blocked-users` unconditionally blocks content from listed GitHub usernames, regardless of `min-integrity` or any labels. Blocked items receive an effective integrity of `blocked` (below `none`) and are always denied.
+
+```aw wrap
+tools:
+  github:
+    min-integrity: none
+    blocked-users:
+      - "spam-bot"
+      - "compromised-account"
+```
+
+Use this to suppress content from known-bad accounts — automated bots, compromised users, or external contributors pending security review.
+
+### Promoting items via labels
+
+`approval-labels` promotes items bearing any listed GitHub label to `approved` integrity, enabling human-review workflows where a trusted reviewer labels content to signal it is safe for the agent.
+
+```aw wrap
+tools:
+  github:
+    min-integrity: approved
+    approval-labels:
+      - "human-reviewed"
+      - "safe-for-agent"
+```
+
+This is useful when a workflow's `min-integrity` would normally filter out external contributions, but a maintainer can label specific items to let them through.
+
+Promotion only raises integrity — it never lowers it. An item already at `merged` stays at `merged`. Blocked-user exclusion always takes precedence: a blocked user's items remain blocked even if they carry an approval label.
+
+### Effective integrity computation
+
+The gateway computes each item's effective integrity in this order:
+
+1. **Start** with the base integrity level from GitHub metadata (author association, merge status, repo visibility).
+2. **If the author is in `blocked-users`**: effective integrity → `blocked` (always denied).
+3. **Else if the item has a label in `approval-labels`**: effective integrity → max(base, `approved`).
+4. **Else**: effective integrity → base.
+
+The `min-integrity` threshold check is applied after this computation.
+
 ## Default Behavior
 
 For **public repositories**, if no `min-integrity` or `lockdown` is configured, the runtime automatically applies `min-integrity: approved`. This protects public workflows even when additional authentication has not been set up. See [Automatic Minimum-Integrity Protection](/gh-aw/reference/lockdown-mode/#automatic-minimum-integrity-protection) for details.
@@ -115,6 +162,27 @@ tools:
     min-integrity: approved
 ```
 
+**Block specific users while allowing all other content:**
+
+```aw wrap
+tools:
+  github:
+    min-integrity: none
+    blocked-users:
+      - "known-spam-bot"
+```
+
+**Human-review gate for external contributions:**
+
+```aw wrap
+tools:
+  github:
+    min-integrity: approved
+    approval-labels:
+      - "agent-approved"
+      - "human-reviewed"
+```
+
 ## In Logs and Reports
 
 When an item is filtered by the integrity check, the MCP gateway records a `DIFC_FILTERED` event in the run's `gateway.jsonl` log. Each event includes:
@@ -129,14 +197,14 @@ When an item is filtered by the integrity check, the MCP gateway records a `DIFC
 When gateway metrics are displayed, filtered events appear in a **DIFC Filtered Events** table alongside the standard server usage table:
 
 ```text
-┌─────────────────────────────────────────────────────────────────────────────────────┐
-│ DIFC Filtered Events                                                                │
-├────────────────┬───────────────┬───────────────┬─────────────────────────────────-─┤
-│ Server         │ Tool          │ User          │ Reason                             │
-├────────────────┼───────────────┼───────────────┼────────────────────────────────────┤
-│ github         │ list_issues   │ new-user      │ Resource has lower integrity than  │
-│                │               │               │ agent requires.                    │
-└────────────────┴───────────────┴───────────────┴────────────────────────────────────┘
+┌────────────────────────────────────────────────────────────────────────────────────┐
+│ DIFC Filtered Events                                                               │
+├────────────────┬───────────────┬───────────────┬──────────────────────────────────-┤
+│ Server         │ Tool          │ User          │ Reason                            │
+├────────────────┼───────────────┼───────────────┼───────────────────────────────────┤
+│ github         │ list_issues   │ new-user      │ Resource has lower integrity than │
+│                │               │               │ agent requires.                   │
+└────────────────┴───────────────┴───────────────┴───────────────────────────────────┘
 ```
 
 The `Total DIFC Filtered` count in the summary line shows how many items were suppressed during the run.

From 7f71526768b4b427b56a7e5e58030db293983cfe Mon Sep 17 00:00:00 2001
From: Landon Cox <landon.cox@microsoft.com>
Date: Fri, 20 Mar 2026 17:07:54 -0700
Subject: [PATCH 4/4] docs: add blocked level to integrity hierarchy

Show blocked as a distinct level below none in the hierarchy diagram
and levels table. Clarify it is not a configurable min-integrity value
but is assigned automatically via blocked-users.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
 docs/src/content/docs/reference/integrity.md | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/docs/src/content/docs/reference/integrity.md b/docs/src/content/docs/reference/integrity.md
index 8e9e25d83c4..682e7e38f63 100644
--- a/docs/src/content/docs/reference/integrity.md
+++ b/docs/src/content/docs/reference/integrity.md
@@ -32,16 +32,25 @@ tools:
 
 ## Integrity Levels
 
+The full integrity hierarchy, from highest to lowest:
+
+```text
+merged > approved > unapproved > none > blocked
+```
+
 | Level | What qualifies at this level |
 |-------|------------------------------|
 | `merged` | Pull requests that have been merged, and commits reachable from the default branch (any author) |
 | `approved` | Objects authored by `OWNER`, `MEMBER`, or `COLLABORATOR`; non-fork PRs on public repos; all items in private repos; trusted platform bots (e.g., dependabot) |
 | `unapproved` | Objects authored by `CONTRIBUTOR` or `FIRST_TIME_CONTRIBUTOR` |
 | `none` | All objects, including `FIRST_TIMER` and users with no association (`NONE`) |
+| `blocked` | Items authored by users in `blocked-users` — always denied, cannot be promoted |
+
+The four configurable levels (`merged`, `approved`, `unapproved`, `none`) are cumulative and ordered from most restrictive to least. Setting `min-integrity: approved` means only items at `approved` level **or higher** (`merged`) reach the agent. Items at `unapproved` or `none` are filtered out.
 
-Levels are cumulative and ordered from most restrictive to least. Setting `min-integrity: approved` means only items at `approved` level **or higher** (`merged`) reach the agent. Items at `unapproved` or `none` are filtered out.
+`blocked` is not a configurable `min-integrity` value — it is assigned automatically to items from users in the `blocked-users` list and is always denied regardless of the configured threshold.
 
-**`merged`** is the strictest level. A pull request qualifies as `merged` when it has been merged into the target branch. Commits qualify when they are reachable from the default branch. This is useful for workflows that should only act on production content.
+**`merged`** is the strictest configurable level. A pull request qualifies as `merged` when it has been merged into the target branch. Commits qualify when they are reachable from the default branch. This is useful for workflows that should only act on production content.
 
 **`approved`** corresponds to users who have a formal trust relationship with the repository: owners, members, and collaborators. Items in private repositories are automatically elevated to `approved` (since only collaborators can access them). Recognized platform bots such as dependabot and github-actions also receive `approved` integrity. This is the most common choice for public repository workflows.
 
@@ -49,6 +58,8 @@ Levels are cumulative and ordered from most restrictive to least. Setting `min-i
 
 **`none`** allows all content through. Use this deliberately, with appropriate safeguards, for workflows designed to process untrusted input — such as triage bots or spam detection.
 
+**`blocked`** sits below `none` and represents an explicit negative trust decision. Items at this level are unconditionally denied — even `min-integrity: none` does not allow them through. See [Blocking specific users](#blocking-specific-users) below.
+
 ## Adjusting Integrity Per-Item
 
 Beyond setting a minimum level, you can override integrity for specific authors or labels.
