Skip to content

Update make release to accept bump type as positional argument#34

Merged
pelikhan merged 2 commits into
mainfrom
copilot/update-make-release-command
Jan 6, 2026
Merged

Update make release to accept bump type as positional argument#34
pelikhan merged 2 commits into
mainfrom
copilot/update-make-release-command

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 6, 2026

Changed make release syntax from make release BUMP=patch to make release patch and corrected the workflow URL.

Changes

  • Makefile syntax: Uses $(filter-out $@,$(MAKECMDGOALS)) to capture bump type as positional argument instead of Makefile variable
  • Catch-all pattern: Added %: @: rule to prevent make from treating the argument as a separate target
  • Workflow URL: Updated from release.md to release.lock.yml
  • Help text: Updated to reflect new usage pattern

Usage

# Old syntax (no longer works)
make release BUMP=patch

# New syntax
make release patch
make release minor
make release major

Error handling remains unchanged - validates bump type and prompts for confirmation before creating tags.

Original prompt

Update make release:


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

…x workflow URL

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Update make release command syntax for version bumps Update make release to accept bump type as positional argument Jan 6, 2026
Copilot AI requested a review from pelikhan January 6, 2026 23:04
@pelikhan pelikhan marked this pull request as ready for review January 6, 2026 23:07
@pelikhan pelikhan merged commit a49ecd2 into main Jan 6, 2026
@pelikhan pelikhan deleted the copilot/update-make-release-command branch January 6, 2026 23:07
lpcox pushed a commit that referenced this pull request Jan 8, 2026
* Initial plan

* Update make release to accept bump type as positional argument and fix workflow URL

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
pelikhan added a commit that referenced this pull request Feb 4, 2026
OAuth discovery requests to `/.well-known/oauth-authorization-server`
hang instead of returning 404, causing Codex rmcp client to timeout
after 15s per server. Gateway only registers handler at
`/mcp/.well-known/oauth-authorization-server`.

## Changes

- **Route registration**: Add handler at
`/.well-known/oauth-authorization-server` in both unified
(`transport.go`) and routed (`routed.go`) modes
- **Handler reuse**: Both paths now use existing
`handleOAuthDiscovery()` that returns 404
- **Test coverage**: Added test cases for root-level and MCP-prefixed
paths (GET/POST methods)

## Implementation

```go
// OAuth discovery endpoints - return 404 since we don't use OAuth
// Standard path for OAuth discovery (per RFC 8414)
mux.Handle("/.well-known/oauth-authorization-server", withResponseLogging(handleOAuthDiscovery()))
// MCP-prefixed path for backward compatibility
mux.Handle("/mcp/.well-known/oauth-authorization-server", withResponseLogging(handleOAuthDiscovery()))
```

Result: OAuth discovery now fails fast with immediate 404 instead of
timing out.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build3835057396/b270/launcher.test
/tmp/go-build3835057396/b270/launcher.test
-test.testlogfile=/tmp/go-build3835057396/b270/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true g_.a dler at
/.well-known/oauth-authorization-server for both unified and routed
modes
- Prevents req--norc x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3835057396/b258/config.test
/tmp/go-build3835057396/b258/config.test
-test.testlogfile=/tmp/go-build3835057396/b258/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ache/go/1.25.6/x64/src/runtime/cgo` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build3835057396/b270/launcher.test
/tmp/go-build3835057396/b270/launcher.test
-test.testlogfile=/tmp/go-build3835057396/b270/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true g_.a dler at
/.well-known/oauth-authorization-server for both unified and routed
modes
- Prevents req--norc x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build3835057396/b270/launcher.test
/tmp/go-build3835057396/b270/launcher.test
-test.testlogfile=/tmp/go-build3835057396/b270/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true g_.a dler at
/.well-known/oauth-authorization-server for both unified and routed
modes
- Prevents req--norc x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3835057396/b279/mcp.test
/tmp/go-build3835057396/b279/mcp.test
-test.testlogfile=/tmp/go-build3835057396/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true g_.a
64/src/crypto/internal/boring/bbig/big.go
df11d1ebad5122b89293a9cf3b8353f09e1d0c3b3841ebf6471/log.json -g&#34;
&#34;-lresolv&#34; ernal/sys -I 64/pkg/tool/linux_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>OAuth discovery requests hang instead of returning
404</issue_title>
> <issue_description>## Summary
> 
> OAuth discovery requests to `/.well-known/oauth-authorization-server`
hang indefinitely instead of returning a quick 404 response. This causes
Codex MCP connections to timeout after 15 seconds per server.
> 
> ## Problem
> 
> The Codex rmcp client (Rust MCP client) attempts OAuth discovery at
the **standard path**:
> ```
> GET http://host.docker.internal/.well-known/oauth-authorization-server
> ```
> 
> But the MCP Gateway registers the OAuth handler at:
> ```
> /mcp/.well-known/oauth-authorization-server
> ```
> 
> Since there's no handler at `/.well-known/...`, the request has no
matching route and hangs instead of returning 404.
> 
> ## Evidence
> 
> ### Smoke-codex workflow run:
https://github.com/github/gh-aw/actions/runs/21688558782
> 
> **Error pattern:**
> ```
> DEBUG session_init: codex_rmcp_client::auth_status: OAuth discovery
requests failed for
> http://host.docker.internal:80/mcp/playwright: error sending request
for url
> (http://host.docker.internal/.well-known/oauth-authorization-server)
> 
> Caused by:
>     operation timed out
> ```
> 
> **Result:**
> - OAuth discovery times out (15 seconds per server)
> - 4 of 6 MCP servers fail to connect
> - Only tavily and safeoutputs succeed (race condition - they complete
before timeout exhausts resources)
> 
> **Firewall logs confirm traffic reaches gateway:**
> ```
> ▼ 11 requests | 11 allowed | 0 blocked | 1 unique domain
> | Domain              | Allowed | Denied |
> |---------------------|---------|--------|
> | host.docker.internal | 11      | 0      |
> ```
> 
> ### Comparison with working run
> 
> In run 21653900083 (before chroot mode), using IP address 172.30.0.1,
OAuth discovery was NOT attempted and all 6 MCP servers connected
successfully:
> ```
> ready: ["safeoutputs", "safeinputs", "github", "playwright", "tavily",
"serena"]
> ```
> 
> ## Current Route Registration
> 
> From `internal/server/transport.go`:
> 
> | Route | Handler |
> |-------|---------|
> | `/mcp/.well-known/oauth-authorization-server` | OAuth handler
(returns 404) |
> | `/mcp/` and `/mcp` | StreamableHTTPHandler |
> | `/health` | Health check |
> | `/close` | Graceful shutdown |
> | `/.well-known/*` | **NO HANDLER** ← causes hang |
> 
> ## Proposed Fix
> 
> Add a handler for OAuth discovery at the standard path (without
`/mcp/` prefix):
> 
> ```go
> // In internal/server/transport.go, add alongside existing routes:
> mux.HandleFunc("/.well-known/oauth-authorization-server", func(w
http.ResponseWriter, r *http.Request) {
>     http.NotFound(w, r)
> })
> ```
> 
> This ensures OAuth discovery requests get an immediate 404 response
instead of hanging.
> 
> ## Impact
> 
> This fix would:
> 1. Make OAuth discovery fail fast (instant 404 instead of 15s timeout)
> 2. Allow all 6 MCP servers to connect successfully in Codex workflows
> 3. Fix smoke-codex CI failures
> 
> ## Related
> 
> - gh-aw PR github/gh-aw-mcpg#13792: Removed hardcoded IP from Codex
config (firewall fix - separate issue)</issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #672

<!-- START COPILOT CODING AGENT TIPS -->
---

✨ Let Copilot coding agent [set things up for
you](https://github.com/github/gh-aw-mcpg/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.
lpcox added a commit that referenced this pull request Feb 5, 2026
Duplicate code analysis identified ~54 lines of duplication across 2
patterns in the DIFC and config validation modules.

## Changes

### DIFC Label Constructors
Extracted common label-with-tags creation pattern into
`newLabelWithTags()` helper:

```go
// Before: Duplicated logic in both constructors
func NewSecrecyLabelWithTags(tags []Tag) *SecrecyLabel {
    label := NewSecrecyLabel()
    label.Label.AddAll(tags)
    return label
}

func NewIntegrityLabelWithTags(tags []Tag) *IntegrityLabel {
    label := NewIntegrityLabel()
    label.Label.AddAll(tags)
    return label
}

// After: Single helper, constructors simplified
func newLabelWithTags(tags []Tag) *Label {
    label := NewLabel()
    label.AddAll(tags)
    return label
}

func NewSecrecyLabelWithTags(tags []Tag) *SecrecyLabel {
    return &SecrecyLabel{Label: newLabelWithTags(tags)}
}

func NewIntegrityLabelWithTags(tags []Tag) *IntegrityLabel {
    return &IntegrityLabel{Label: newLabelWithTags(tags)}
}
```

Eliminates ~8 lines of duplication in `internal/difc/labels.go`.

### Docker Inspect Wrappers
Analysis confirmed `checkPortMapping()`, `checkStdinInteractive()`, and
`checkLogDirMounted()` already share the `runDockerInspect()` helper.
Each function has distinct domain logic and return types. No further
abstraction warranted.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build4007704820/b274/launcher.test
/tmp/go-build4007704820/b274/launcher.test
-test.testlogfile=/tmp/go-build4007704820/b274/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ache/go/1.25.6/x64/src/runtime/cgo .cfg 64/pkg/tool/linux_amd64/vet -p
vendor/golang.or-unsafeptr=false -lang=go1.25
64/pkg/tool/linux_amd64/vet -I 8340911/b183/ -I rgo/bin/as -g&#34;
&#34;-lresolv&#34; --64 -o 8340911/b183/` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3364410036/b001/config.test
/tmp/go-build3364410036/b001/config.test
-test.testlogfile=/tmp/go-build3364410036/b001/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go
ps140/fips140.go-imultiarch 64/pkg/tool/linux86_64-linux-gnu` (dns
block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build4007704820/b274/launcher.test
/tmp/go-build4007704820/b274/launcher.test
-test.testlogfile=/tmp/go-build4007704820/b274/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ache/go/1.25.6/x64/src/runtime/cgo .cfg 64/pkg/tool/linux_amd64/vet -p
vendor/golang.or-unsafeptr=false -lang=go1.25
64/pkg/tool/linux_amd64/vet -I 8340911/b183/ -I rgo/bin/as -g&#34;
&#34;-lresolv&#34; --64 -o 8340911/b183/` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build4007704820/b274/launcher.test
/tmp/go-build4007704820/b274/launcher.test
-test.testlogfile=/tmp/go-build4007704820/b274/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ache/go/1.25.6/x64/src/runtime/cgo .cfg 64/pkg/tool/linux_amd64/vet -p
vendor/golang.or-unsafeptr=false -lang=go1.25
64/pkg/tool/linux_amd64/vet -I 8340911/b183/ -I rgo/bin/as -g&#34;
&#34;-lresolv&#34; --64 -o 8340911/b183/` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build4007704820/b283/mcp.test
/tmp/go-build4007704820/b283/mcp.test
-test.testlogfile=/tmp/go-build4007704820/b283/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/net red-by:
lpcox &lt;15877973&#43;lpcox@users.noreply.github.com&gt;
ache/go/1.25.6/x64/pkg/tool/linux_amd64/vet -p
crypto/internal/-unsafeptr=false -lang=go1.25 01.o` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>[duplicate-code] Duplicate Code Analysis Report -
f550849</issue_title>
> <issue_description>*Analysis of commit
f550849*
> 
> ## Summary
> 
> This analysis identified **2 significant duplication patterns** across
the Go codebase, affecting the DIFC (Decentralized Information Flow
Control) module and configuration validation code. A total of
approximately **54 lines** of meaningful duplicated code were detected.
> 
> ## Detected Patterns
> 
> This analysis found 2 significant duplication patterns requiring
refactoring:
> 
> 1. **DIFC Label Constructor Duplication** - Severity: Medium - See
sub-issue #aw_xyz789ghi012
> 2. **Docker Inspect Wrapper Functions** - Severity: Medium - See
sub-issue #aw_mno345pqr678
> 
> ## Overall Impact
> 
> - **Total Duplicated Lines**: ~54 lines across 2 patterns
> - **Affected Files**: 2 files (`internal/difc/labels.go`,
`internal/difc/agent.go`, `internal/config/validation_env.go`)
> - **Maintainability Risk**: Medium - Duplication increases risk of
inconsistent updates
> - **Refactoring Priority**: Medium - Both patterns are in active
development areas
> 
> ## Next Steps
> 
> 1. Review individual pattern sub-issues for detailed analysis
> 2. Prioritize refactoring based on severity and impact
> 3. Create implementation plan for highest priority patterns
> 4. Consider using Go generics or helper functions to reduce
duplication
> 
> ## Analysis Metadata
> 
> - **Analyzed Files**: 60 Go files (excluding tests, workflows, and
agent configs)
> - **Detection Method**: Semantic code analysis using grep and manual
code review
> - **Commit**: f550849
> - **Analysis Date**: 2026-02-05T03:03:56Z
> - **Triggered by**: `@lpcox`
> 
> 
> 
> 
> > AI generated by [Duplicate Code
Detector](https://github.com/github/gh-aw-mcpg/actions/runs/21697098717)
> > - [x] expires <!-- gh-aw-expires: 2026-02-12T03:07:40.520Z --> on
Feb 12, 2026, 3:07 AM UTC
> 
> <!-- gh-aw-agentic-workflow: Duplicate Code Detector, engine: copilot,
run: https://github.com/github/gh-aw-mcpg/actions/runs/21697098717 -->
> 
> <!-- gh-aw-workflow-id: duplicate-code-detector
--></issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>


> **Custom agent used: agentic-workflows**
> GitHub Agentic Workflows (gh-aw) - Create, debug, and upgrade
AI-powered workflows with intelligent prompt routing



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #678

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).
lpcox added a commit that referenced this pull request Feb 8, 2026
#844)

Nightly stress test detected configuration errors in two MCP servers:
filesystem expected directories as CLI arguments but received
environment variables, and playwright had redundant host list entries.

## Changes

**filesystem server**
- Changed from `env.ALLOWED_PATHS` to `entrypointArgs: ["/workspace"]`
- Server requires directory paths as positional arguments after
container name

**playwright server**  
- Simplified allowed-hosts/origins from
`localhost;localhost:*;127.0.0.1;127.0.0.1:*` to
`localhost:*;127.0.0.1:*`
- Removed redundant non-wildcard entries

## Configuration structure

Gateway converts workflow YAML to Docker commands following this
pattern:
```bash
docker run [args...] <container> [entrypointArgs...]
```

- `args`: Docker runtime flags (e.g., `--init`, `--network host`) -
before container
- `entrypointArgs`: Application arguments - after container

## Testing

Added `TestLoadFromStdin_FilesystemServerConfig` and
`TestLoadFromStdin_PlaywrightServerConfig` to validate argument
placement and prevent similar configuration errors.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build1254119737/b275/launcher.test
/tmp/go-build1254119737/b275/launcher.test
-test.testlogfile=/tmp/go-build1254119737/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
/opt/hostedtoolcache/go/1.25.6/x64/src/runtime/cgo 6765506/b184/
ache/Python/3.12.12/x64/bin/as --gdwarf-5 --64 -o as 6765�� d -n 10 -I
docker-buildx --gdwarf-5 --64 -o docker-buildx` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3908585129/b001/config.test
/tmp/go-build3908585129/b001/config.test
-test.testlogfile=/tmp/go-build3908585129/b001/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go1.25.6 -c=4
-nolocalimports -importcfg /tmp/go-build2196765506/b210/importcfg -pack
/opt/hostedtoolcache/go/1.25.6/x64/src/net/http/httptest/httptest.go
conf�� go k/gh-aw-mcpg/gh-aw-mcpg/tools.go--gdwarf2
ache/Python/3.12.12/x64/bin/bash--64
k/gh-aw-mcpg/gh-/opt/hostedtoolcache/go/1.25.6/x64/pkg/tool/linux_amd64/compile
k/gh-aw-mcpg/gh--o k/gh-aw-mcpg/gh-/tmp/go-build2196765506/b125/_pkg_.a
.o` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build1254119737/b275/launcher.test
/tmp/go-build1254119737/b275/launcher.test
-test.testlogfile=/tmp/go-build1254119737/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
/opt/hostedtoolcache/go/1.25.6/x64/src/runtime/cgo 6765506/b184/
ache/Python/3.12.12/x64/bin/as --gdwarf-5 --64 -o as 6765�� d -n 10 -I
docker-buildx --gdwarf-5 --64 -o docker-buildx` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build1254119737/b275/launcher.test
/tmp/go-build1254119737/b275/launcher.test
-test.testlogfile=/tmp/go-build1254119737/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
/opt/hostedtoolcache/go/1.25.6/x64/src/runtime/cgo 6765506/b184/
ache/Python/3.12.12/x64/bin/as --gdwarf-5 --64 -o as 6765�� d -n 10 -I
docker-buildx --gdwarf-5 --64 -o docker-buildx` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1254119737/b284/mcp.test
/tmp/go-build1254119737/b284/mcp.test
-test.testlogfile=/tmp/go-build1254119737/b284/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
/tmp/go-build2196765506/b218/_pkg_.a 6765506/b184/ p/bin/as -p
github.com/githu-unsafeptr=false -lang=go1.25 as 6765�� d -n 10
--debug-prefix-map ache/go/1.25.6/x64/pkg/tool/linux_amd64/vet -I
/opt/hostedtoolcmod -I ache/go/1.25.6/x64/pkg/tool/linuf() { test
&#34;$1&#34; = get &amp;&amp; echo &#34;******&#34;; }; f sto-w` (dns
block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>


----

*This section details on the original issue you should resolve*

<issue_title>[mcp-stress-test] Server Configuration Failures Detected -
filesystem & playwright</issue_title>
<issue_description>The nightly stress test detected 2 servers with
configuration errors (not authentication issues).

## Test Summary

- **Test Session:** stress-test-20260208-034257
- **Test Date:** 2026-02-08T03:42:57Z
- **Total Configuration Failures:** 2

## Failed Servers

### 1. filesystem - Command Arguments Error

**Container:** mcp/filesystem

**Issue Type:** Configuration Error

**Error:**
``````
Usage: mcp-server-filesystem (allowed-directory) [additional-directories...]
``````

**Analysis:**
The filesystem server expects allowed directories as positional
command-line arguments, but the configuration is passing them as
environment variables (`ALLOWED_PATHS`). The docker command structure
needs to be updated.

**Current Configuration Issue:**
The server is launched with environment variable but expects positional
args.

**Suggested Fix:**
Update configuration to pass directories as positional arguments:

``````json
{
  "filesystem": {
    "type": "stdio",
    "container": "mcp/filesystem",
    "args": ["/workspace", "/additional/path"]
  }
}
``````

Or update the docker args to include the directory paths:
```````json
{
  "filesystem": {
    "type": "stdio",
    "command": "docker",
    "args": ["run", "--rm", "-i", "-v", "/tmp/mcp-test-fs:/workspace:rw", "mcp/filesystem", "/workspace"]
  }
}
``````

**Suggested Investigation:**
- [ ] Review filesystem server documentation for correct argument format
- [ ] Update gateway configuration to pass directories correctly
- [ ] Test with simple single directory first
- [ ] Consider if server should be updated to support env vars

---

### 2. playwright - Duplicate Flag Error

**Container:** mcr.microsoft.com/playwright/mcp

**Issue Type:** Configuration Error

**Error:**
``````
error: unknown option '--init'
``````

**Analysis:**
The docker command includes the `--init` flag twice - once as a docker
option (correct) and once passed to the playwright binary (incorrect).
The playwright binary doesn't recognize the `--init` flag and fails.

**Current Configuration Issue:**
``````
docker run --rm -i --init --network host mcr.microsoft.com/playwright/mcp --output-dir ... --init --network host
```````

Notice `--init` and `--network host` appear twice.

**Suggested Fix:**
Remove the duplicate flags from the playwright server arguments:

``````json
{
  "playwright": {
    "type": "stdio",
    "command": "docker",
    "args": [
      "run", "--rm", "-i",
      "--init",
      "--network", "host",
      "-v", "/tmp/gh-aw/mcp-logs:/tmp/gh-aw/mcp-logs:rw",
      "mcr.microsoft.com/playwright/mcp",
      "--output-dir", "/tmp/gh-aw/mcp-logs/playwright",
      "--allowed-hosts", "localhost,localhost:*,127.0.0.1,127.0.0.1:*",
      "--allowed-origins", "localhost;localhost:*;127.0.0.1;127.0.0.1:*"
    ]
  }
}
``````

**Suggested Investigation:**
- [ ] Review playwright MCP server documentation
- [ ] Remove duplicate `--init` and `--network host` from args array
- [ ] Verify correct flag order for playwright binary
- [ ] Test with corrected configuration

---

## Gateway Logs

From the gateway logs, both issues are clearly configuration-related,
not authentication or protocol issues:

**filesystem:**
- Server expects CLI args but receives env vars
- Quick fix: restructure docker command args

**playwright:**
- Duplicate flags passed to both docker and playwright binary
- Quick fix: remove duplicate flags from args array

## Test Configuration Used

The test used the following configuration:
- Startup Timeout: 60s
- Tool Timeout: 30s
- Test Method: Sequential server testing
- Gateway: Successfully handled all requests

## Impact

These configuration issues prevent 2 MCP servers from launching:
1. **filesystem** - Would provide file system access if configured
correctly
2. **playwright** - Would provide browser automation if configured
correctly

Both are fixable with configuration changes and don't require code
modifications.

## Next Steps

1. **Priority: High** - Fix filesystem configuration
   - Update docker args to pass directories as positional arguments
   - Test with `/workspace` mount
   
2. **Priority: High** - Fix playwright configuration
   - Remove duplicate `--init` and `--network host` flags
   - Verify flag order matches playwright binary expectations

3. Re-run stress test to verify fixes
4. Update documentation with correct configuration examples

---
*Generated by Nightly MCP Stress Test*  
*Test Session: stress-test-20260208-034257*

**Full Test Results:** See workflow run artifacts at
`/tmp/mcp-stress-results/`




> AI generated by [Nightly MCP Server Stress
Test](https://github.com/github/gh-aw-mcpg/actions/runs/21791681391)

<!-- gh-aw-agentic-workflow: Nightly MCP Server Stress Test, engine:
copilot, run:
https://github.com/github/gh-aw-mcpg/actions/runs/2179168139...

</details>


> **Custom agent used: agentic-workflows**
> GitHub Agentic Workflows (gh-aw) - Create, debug, and upgrade
AI-powered workflows with intelligent prompt routing



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #843

<!-- START COPILOT CODING AGENT TIPS -->
---

✨ Let Copilot coding agent [set things up for
you](https://github.com/github/gh-aw-mcpg/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.
lpcox added a commit that referenced this pull request Feb 11, 2026
The Language Support Tester workflow documentation hardcoded
`/workspace/` paths, preventing the agent from locating test samples at
runtime. GitHub Actions workspace paths vary by environment (e.g.,
`/home/runner/work/{repo}/{repo}`).

## Changes

- **Updated path references in
`.github/agentics/language-support-tester.md`**:
  - Changed hardcoded `/workspace/` paths to `{workspace}` placeholder
- Added instructions to use workspace path from `github-context` section
  - Applied to JavaScript/TypeScript test samples path
  - Applied to Python test samples path
  - Updated "Important Notes" section references

The agent now receives the actual runtime workspace path via
`__GH_AW_GITHUB_WORKSPACE__` in the github-context and can correctly
construct paths to test samples:

```markdown
- Use the test samples at `{workspace}/test/serena-mcp-tests/samples/js_project/` (use the workspace path from github-context)
```

## Notes

Test sample files already exist in the repository with expected content
(`Calculator` class, `add` method, `format_number` function,
`package.json`). No code changes required.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build380999041/b279/launcher.test
/tmp/go-build380999041/b279/launcher.test
-test.testlogfile=/tmp/go-build380999041/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
HEAD ache/go/1.25.6/x64/pkg/tool/linu-o it base64
/usr/bin/dirname/tmp/go-build380999041/b263/_pkg_.a 8.o comm�� /go-build
Fix workflow docgithub.com/github/gh-aw-mcpg/internal/config
x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build380999041/b264/config.test
/tmp/go-build380999041/b264/config.test
-test.testlogfile=/tmp/go-build380999041/b264/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/c-c=4
kdf/cast.go ache/go/1.25.6/x-importcfg cal/bin/git base64 /usr/sbin/git
6.o -c 64/src/runtime/cgo tf &#34;%s%s&#34;, sep, $0; sep=RS }
x_amd64/compile --abbrev-ref HEAD /usr/bin/base64 x_amd64/compile` (dns
block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build380999041/b279/launcher.test
/tmp/go-build380999041/b279/launcher.test
-test.testlogfile=/tmp/go-build380999041/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
HEAD ache/go/1.25.6/x64/pkg/tool/linu-o it base64
/usr/bin/dirname/tmp/go-build380999041/b263/_pkg_.a 8.o comm�� /go-build
Fix workflow docgithub.com/github/gh-aw-mcpg/internal/config
x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build380999041/b279/launcher.test
/tmp/go-build380999041/b279/launcher.test
-test.testlogfile=/tmp/go-build380999041/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
HEAD ache/go/1.25.6/x64/pkg/tool/linu-o it base64
/usr/bin/dirname/tmp/go-build380999041/b263/_pkg_.a 8.o comm�� /go-build
Fix workflow docgithub.com/github/gh-aw-mcpg/internal/config
x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build380999041/b288/mcp.test
/tmp/go-build380999041/b288/mcp.test
-test.testlogfile=/tmp/go-build380999041/b288/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 737903/b083/_pkg_.a
JWKP/08bK8wSDgKwIadp3JWKP x_amd64/vet cal/bin/git /unix /x64=/_/GOROOT
x_amd64/vet o_.o�� ache/go/1.25.6/x-errorsas
ache/go/1.25.6/x-ifaceassert x_amd64/vet 737903/b083/symabash HEAD
ndor/bin/git x_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>[language-support] Missing test samples for
TypeScript/JavaScript and Python language support testing</issue_title>
> <issue_description>## Summary
> 
> The Language Support Tester workflow references test sample
directories that do not exist in the repository, preventing proper
testing of TypeScript/JavaScript and Python language support with the
Serena MCP server.
> 
> ## Missing Directories
> 
> The following test sample directories referenced in
`.github/agentics/language-support-tester.md` are missing:
> 
> - `/workspace/test/serena-mcp-tests/samples/js_project/`
> - `/workspace/test/serena-mcp-tests/samples/python_project/`
> 
> ## Impact
> 
> - **Go language support**: ✅ Successfully tested with existing Go
files
> - **TypeScript/JavaScript support**: ❌ Cannot test - no test samples
exist
> - **Python support**: ❌ Cannot test - no test samples exist
> 
> ## Test Results
> 
> ### Go Language Support (✅ Working)
> 
> Successfully tested Go language support using the main repository
code:
> - `get_symbols_overview` on `main.go` returned functions: `main`,
`buildVersionString`, and constant `shortHashLength`
> - `find_symbol` successfully found the `main` function with correct
location and signature
> - `find_symbol` successfully found the `Version` variable in
`version.go` with complete info including documentation
> 
> ### TypeScript/JavaScript Support (⚠️ Unable to Test)
> 
> The referenced test directory
`/workspace/test/serena-mcp-tests/samples/js_project/` does not exist.
The repository contains no JavaScript or TypeScript files for testing.
> 
> ### Python Support (⚠️ Unable to Test)
> 
> The referenced test directory
`/workspace/test/serena-mcp-tests/samples/python_project/` does not
exist. The repository contains no Python files for testing.
> 
> ## Reproduction Steps
> 
> 1. Run the Language Support Tester workflow
> 2. Agent attempts to locate test samples at the documented paths
> 3. Paths do not exist in the repository
> 
> ## Recommended Solution
> 
> Create the missing test sample directories with appropriate test
files:
> 
> 1. Create `/workspace/test/serena-mcp-tests/samples/js_project/` with:
>    - `index.js` or `index.ts` with sample functions/classes
>    - `package.json` with project metadata
> 
> 2. Create `/workspace/test/serena-mcp-tests/samples/python_project/`
with:
>    - `calculator.py` with a `Calculator` class and `add` method
>    - `utils.py` with utility functions like `format_number`
> 
> Alternatively, update the testing workflow documentation to reference
existing test files or clarify that only Go language support needs
testing.
> 
> ## Additional Context
> 
> - Serena MCP server version: `ghcr.io/github/serena-mcp-server:latest`
> - Workflow: `.github/workflows/language-support-tester.lock.yml`
> - Task specification: `.github/agentics/language-support-tester.md`
> - Active project: `gh-aw-mcpg` (Go language configured)
> 
> 
> 
> 
> > AI generated by [Language Support
Tester](https://github.com/github/gh-aw-mcpg/actions/runs/21861851918)
> > - [x] expires <!-- gh-aw-expires: 2026-02-17T10:55:01.059Z --> on
Feb 17, 2026, 10:55 AM UTC
> 
> <!-- gh-aw-agentic-workflow: Language Support Tester, engine: copilot,
run: https://github.com/github/gh-aw-mcpg/actions/runs/21861851918 -->
> 
> <!-- gh-aw-workflow-id: language-support-tester
--></issue_description>
> 
> ## Comments on the Issue (you are @claude[agent] in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #875
lpcox added a commit that referenced this pull request Feb 11, 2026
…ag validation, and lifecycle hooks (#882)

Implements Priority 1 and 2 recommendations from Go Fan report for
github.com/spf13/cobra v1.10.2. Leverages new Cobra features for cleaner
CLI code and better reliability.

## Context-based graceful shutdown

Replace manual signal handling with `signal.NotifyContext` for proper
cancellation propagation:

```go
// Before: manual signal channel
ctx, cancel := context.WithCancel(context.Background())
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)

// After: v1.10.0 pattern
ctx, cancel := signal.NotifyContext(cmd.Context(), os.Interrupt, syscall.SIGTERM)
```

- HTTP server shutdown with 5s timeout via `httpServer.Shutdown(ctx)`
- Context cancellation propagates through unified server

## Declarative flag validation

Replace manual preRun validation with Cobra's built-in validation
groups:

```go
// Flag validation groups
cmd.MarkFlagsMutuallyExclusive("routed", "unified")
cmd.MarkFlagsOneRequired("config", "config-stdin")
```

- Removes 5 lines of manual validation logic from `preRun`
- Produces consistent error messages: `"at least one of the flags in the
group [config config-stdin] is required"`
- Updates integration test to expect new error format

## Lifecycle hooks

- Add `PersistentPostRun` hook for logger cleanup
- Moves defer calls from `run()` to `postRun()` for cleaner separation
- Logger initialization in run, cleanup in postRun

## Enhanced completions

Add ActiveHelp hints for better shell completion UX:

```go
cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
    return cobra.AppendActiveHelp(nil,
        "Tip: Use --config <file> for file-based config or --config-stdin for piped JSON config"),
        cobra.ShellCompDirectiveNoFileComp
}
```

## Version template

Custom formatting: `MCPG Gateway {{.Version}}` instead of default
output.

## Tests

- Context cancellation behavior
- Flag validation group registration
- Version template and postRun hook presence

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build884163099/b275/launcher.test
/tmp/go-build884163099/b275/launcher.test
-test.testlogfile=/tmp/go-build884163099/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go 95WK6prK2
x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build884163099/b260/config.test
/tmp/go-build884163099/b260/config.test
-test.testlogfile=/tmp/go-build884163099/b260/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true g_.a HEAD 64/bin/as
TOKEN&#34;; }; f sto/tmp/go-build3472542465/b223/cmd.test go cal/bin/git
512block_amd64.o-test.timeout=10m0s 64/s�� 64/src/runtime/cgo xpwaXSmNs
ache/go/1.25.6/x64/pkg/tool/linu--64 --abbrev-ref 2542465/b013/
.12/x64/bin/git 05.o` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build884163099/b275/launcher.test
/tmp/go-build884163099/b275/launcher.test
-test.testlogfile=/tmp/go-build884163099/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go 95WK6prK2
x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build884163099/b275/launcher.test
/tmp/go-build884163099/b275/launcher.test
-test.testlogfile=/tmp/go-build884163099/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go 95WK6prK2
x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build884163099/b284/mcp.test
/tmp/go-build884163099/b284/mcp.test
-test.testlogfile=/tmp/go-build884163099/b284/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true g_.a HEAD
x_amd64/vet --abbrev-ref /bidi git x_amd64/vet 64/s��
64/src/runtime/cgo1.25.6 V8YDPttZl inux.go esnew.go ocknew.go nix_cgo.go
nix_cgo_res.go` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>


----

*This section details on the original issue you should resolve*

<issue_title>[go-fan] Go Module Review:
github.com/spf13/cobra</issue_title>
<issue_description># 🐹 Go Fan Report: Cobra CLI Framework

## Module Overview

**Cobra** (github.com/spf13/cobra) is the industry-standard CLI
framework for Go, powering tools like kubectl, hugo, and GitHub CLI. It
provides a powerful structure for building modern command-line
applications with commands, subcommands, flags, and shell completions.

**Current Version**: v1.10.2 ✅ (Latest: v1.10.2, Dec 3, 2025)  
**Repository**: https://github.com/spf13/cobra  
**Popularity**: 40k+ stars

## Current Usage in gh-aw-mcpg

**Well-Implemented** ✅

The project uses Cobra appropriately across 7 files in `internal/cmd/`:

### Files & Structure
- **root.go** - Root command definition and CLI entry point
- **completion.go** - Shell completion commands (bash, zsh, fish,
powershell)
- **flags*.go** (5 files) - Well-organized flag definitions by domain:
  - `flags_core.go` - Core configuration flags
  - `flags_logging.go` - Logging flags
  - `flags_difc.go` - DIFC feature flags (properly uses `MarkHidden()`)
  - `flags_launch.go` - Launch configuration
  - `flags.go` - Registration helpers

### Key Patterns Observed
✅ Clean command structure without unnecessary nesting  
✅ Flags well-organized by functional area  
✅ Proper use of `MarkHidden()` for experimental features  
✅ Comprehensive shell completion support  
✅ Version command integration

## Research Findings

### Recent Cobra Updates (v1.10.x)

#### v1.10.2 (Dec 2025) - Current Version
- **Dependency Cleanup**: Migrated from deprecated `gopkg.in/yaml.v3` to
`go.yaml.in/yaml/v3`
  - Significantly cleaner dependency chain
  - No action required (transparent upgrade)
- Performance improvements (vars → consts)
- Enhanced documentation for repeated flags

#### v1.10.0 (Sep 2025)
- **Context Support**: Commands can now receive and use context for
cancellation/timeout
- **Customizable ShellCompDirective**: Per-command completion behavior
- Improved map flag completions

#### v1.9.0 (Feb 2025)
- **Linker Deadcode Elimination**: Smaller binaries by removing unused
code
- **CompletionFunc Type**: Cleaner completion code
- **CompletionWithDesc Helper**: Easier completions with descriptions
- **ActiveHelp**: Context-sensitive help during tab completion

### Best Practices from Cobra Maintainers

1. **Error Handling**: Use `RunE` instead of `Run` to return errors
properly
2. **Flag Validation**: Use built-in flag groups instead of manual
validation
3. **Context Usage**: Pass context to commands for cancellation and
timeouts
4. **Completions**: Implement dynamic completions for better UX
5. **Lifecycle Hooks**: Use Pre/Post Run hooks for setup and teardown

## Improvement Opportunities

### 🏃 Quick Wins (High Impact, Low Effort)

#### 1. Add Context Support (v1.10.0 feature)
**Priority**: HIGH | **Effort**: LOW

**Current**: No evidence of context usage for graceful shutdown  
**Opportunity**: Enable proper cancellation and timeout handling

``````go
// In root.go
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer cancel()
rootCmd.SetContext(ctx)

// In command RunE
func(cmd *cobra.Command, args []string) error {
    ctx := cmd.Context() // Get context with cancellation support
    // Use ctx for HTTP requests, goroutines, etc.
    return server.Run(ctx)
}
``````

**Benefits**:
- ✅ Proper graceful shutdown on SIGINT/SIGTERM
- ✅ Timeout handling for long-running operations
- ✅ Request tracing and cancellation propagation
- ✅ Better testability with context-based timeouts

#### 2. Use Flag Validation Groups
**Priority**: HIGH | **Effort**: LOW

**Current**: Manual flag validation in code  
**Opportunity**: Declarative validation with better error messages

``````go
// Mutually exclusive flags
cmd.MarkFlagsMutuallyExclusive("config", "stdin-config")

// Flags required together
cmd.MarkFlagsRequiredTogether("log-dir", "enable-file-logging")

// At least one required
cmd.MarkFlagsOneRequired("config", "stdin-config")
``````

**Benefits**:
- ✅ Cleaner code (remove manual validation logic)
- ✅ Consistent, user-friendly error messages
- ✅ Self-documenting flag relationships
- ✅ Less maintenance burden

#### 3. Enhanced Dynamic Completions
**Priority**: MEDIUM | **Effort**: MEDIUM

**Current**: Static shell completions  
**Opportunity**: Dynamic completions for config files, server IDs

``````go
// Config file completion
cmd.RegisterFlagCompletionFunc("config", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
    configs, _ := filepath.Glob("*.toml")
    suggestions := []string{}
    for _, c := range configs {
        suggestions = append(suggestions, c+"\tTOML configuration file")
    }
    return suggestions, cobra.ShellCompDirectiveDefault
})

// Server ID completion (from loaded config)
cmd.RegisterFlagCompletionFunc("server-id", func(cmd *co...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #874
lpcox added a commit that referenced this pull request Feb 11, 2026
…tories (#889)

Nightly documentation reconciliation identified critical discrepancies
between documented and actual default values, plus incomplete internal
directory listings.

## Changes

### Critical: Payload Size Threshold Default
Updated README.md (3 locations) to reflect actual implementation default
of **10240 bytes (10KB)** instead of incorrectly documented 1024 bytes:
- CLI flag description (line 206)
- Flags usage table (line 281)  
- Environment variables table (line 319)

Implementation sources:
- `internal/cmd/flags_logging.go:14` - `defaultPayloadSizeThreshold =
10240`
- `internal/config/config_payload.go:11` - `DefaultPayloadSizeThreshold
= 10240`

### Minor: Complete Internal Directory Listings
Added missing internal packages to project structure documentation:

**CONTRIBUTING.md**: Added 9 missing directories (auth, difc, envutil,
middleware, sys, testutil, version, tty, timeutil) to both tree diagram
and Key Directories section

**AGENTS.md**: Added 7 missing directories (difc, envutil, middleware,
sys, testutil, tty, version) to project structure list

All 16 internal directories now documented in alphabetical order:
`auth`, `cmd`, `config`, `difc`, `envutil`, `guard`, `launcher`,
`logger`, `mcp`, `middleware`, `server`, `sys`, `testutil`, `timeutil`,
`tty`, `version`

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build2370360416/b279/launcher.test
/tmp/go-build2370360416/b279/launcher.test
-test.testlogfile=/tmp/go-build2370360416/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
git ache/go/1.25.6/x64/pkg/tool/linu-o --global r it 08.o -d go git
x_amd64/vet
e/REDACTED/work/gh/opt/hostedtoolcache/go/1.25.6/x64/pkg/tool/linux_amd64/vet
64/src/runtime/c-unsafeptr=false 64/bin/git x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2370360416/b264/config.test
/tmp/go-build2370360416/b264/config.test
-test.testlogfile=/tmp/go-build2370360416/b264/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
HEAD ache/go/1.25.6/x64/pkg/tool/linu-fmessage-length=0 get --global
rgo/bin/git 06.o -d 1.2.0/auth/auth.go git x_amd64/compile get --global
.12/x64/which x_amd64/compile` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build2370360416/b279/launcher.test
/tmp/go-build2370360416/b279/launcher.test
-test.testlogfile=/tmp/go-build2370360416/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
git ache/go/1.25.6/x64/pkg/tool/linu-o --global r it 08.o -d go git
x_amd64/vet
e/REDACTED/work/gh/opt/hostedtoolcache/go/1.25.6/x64/pkg/tool/linux_amd64/vet
64/src/runtime/c-unsafeptr=false 64/bin/git x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build2370360416/b279/launcher.test
/tmp/go-build2370360416/b279/launcher.test
-test.testlogfile=/tmp/go-build2370360416/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
git ache/go/1.25.6/x64/pkg/tool/linu-o --global r it 08.o -d go git
x_amd64/vet
e/REDACTED/work/gh/opt/hostedtoolcache/go/1.25.6/x64/pkg/tool/linux_amd64/vet
64/src/runtime/c-unsafeptr=false 64/bin/git x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2370360416/b288/mcp.test
/tmp/go-build2370360416/b288/mcp.test
-test.testlogfile=/tmp/go-build2370360416/b288/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true g_.a
64/src/internal/bisect/bisect.go--64 86_64/as --global abis p/bin/git
ache/go/1.25.6/x/tmp/go-build2370360416/b059/vet.cfg -d ; then \
$GOPATH/bin/golangci-lint run --timeout=5m || echo &#34;��� Warning:
golangci-lint failed
/opt/hostedtoolcache/go/1.25.6/x64/pkg/tool/linux_amd64/link -wdcAJ1yv
x_amd64/vet rt-size &#39;1280,
7/opt/hostedtoolcache/go/1.25.6/x64/pkg/tool/linux_amd64/vet` (dns
block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>


----

*This section details on the original issue you should resolve*

<issue_title>📚 Documentation Reconciliation Report - February 11,
2026</issue_title>
<issue_description>## Summary

Found **1 critical** and **2 minor** discrepancies between documentation
and implementation during nightly reconciliation check.

- Workflow Run:
[§21890623217](https://github.com/github/gh-aw-mcpg/actions/runs/21890623217)
- Date: February 11, 2026
- Branch: main

## Critical Issues 🔴

Issues that would cause user confusion or broken workflows if followed:

### 1. Payload Size Threshold Default Value Mismatch

**Location:** README.md, lines 206, 281, 319

**Problem:** Documentation states the default payload size threshold is
`1024` bytes (1KB), but the actual implementation uses `10240` bytes
(10KB).

**Actual Behavior:**
- Code: `internal/cmd/flags_logging.go:14` defines
`defaultPayloadSizeThreshold = 10240`
- Code: `internal/config/config_payload.go:11` defines
`DefaultPayloadSizeThreshold = 10240`
- Tests: `internal/cmd/flags_logging_test.go` confirms default is 10240
bytes

**Impact:** Users expecting the documented 1KB threshold will actually
get a 10KB threshold, which could result in:
- More payloads being stored inline than expected (up to 10KB instead of
1KB)
- Less disk I/O than anticipated
- Different memory usage patterns
- Confusion when testing payload storage behavior

**Suggested Fix:** Update README.md to reflect the actual default:

```markdown
# Line 206
- CLI flag: `--payload-size-threshold (bytes)` (default: 10240)

# Line 281
--payload-size-threshold int   Size threshold (in bytes) for storing payloads to disk. Payloads larger than this are stored, smaller ones returned inline (default 10240)

# Line 319
| `MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD` | Size threshold in bytes for payload storage (sets default for `--payload-size-threshold` flag) | `10240` |
```

**Code Reference:**
- `internal/cmd/flags_logging.go:14`
- `internal/config/config_payload.go:11`
- `internal/cmd/flags_logging_test.go:46`

## Minor Issues 🔵

Small inconsistencies or missing details:

### 1. Internal Directory Structure Incomplete in CONTRIBUTING.md

**Location:** CONTRIBUTING.md, lines 206-233 (Project Structure section)

**Problem:** Documentation lists only 7 internal directories, but 16
actually exist.

**Missing Directories:**
- `internal/difc/` - Data Information Flow Control
- `internal/envutil/` - Environment variable utilities
- `internal/middleware/` - HTTP middleware (jq schema processing)
- `internal/sys/` - System utilities
- `internal/testutil/` - Test utilities and helpers
- `internal/tty/` - Terminal detection utilities
- `internal/version/` - Version management

**Impact:** Developers may be unaware of these internal packages when
working on the codebase, potentially duplicating functionality or
missing useful utilities.

**Suggested Fix:** Update the Project Structure section to include all
internal directories with brief descriptions.

**Code Reference:** Directory listing shows all 16 directories exist and
contain working code.

### 2. Internal Directory Structure Incomplete in AGENTS.md

**Location:** AGENTS.md, lines 12-20 (Project Structure section)

**Problem:** Similar to CONTRIBUTING.md, lists only 9 internal
directories instead of 16.

**Missing Directories:** Same as above (difc, envutil, middleware, sys,
testutil, tty, version)

**Impact:** AI agents working with the codebase may not be aware of all
available internal packages.

**Suggested Fix:** Update the Project Structure section to include all
internal directories.

**Code Reference:** Same directory listing as above.

## Documentation Completeness

### Accurate Sections ✅

The following sections were verified and found to be accurate:

- **Go Version Requirement** - Correctly documented as 1.25.0 (matches
`go.mod`)
- **Make Targets** - All 11 documented targets exist and work correctly:
  - `make build`, `test`, `test-unit`, `test-integration`, `test-all`
  - `make lint`, `coverage`, `install`, `agent-finished`
  - `make format`, `clean`
- **Configuration Fields** - All documented fields match code struct
definitions in `internal/config/`
- **Environment Variables** - Correctly documented and extensively used
(140+ references in code)
- **External Links**:
  - MCP Gateway spec link is valid (returns HTTP 200)
  - GitHub token URL is valid (redirects properly)
- **Feature Documentation**:
  - HTTP transport correctly marked as "fully supported"
- Container field requirement for stdio servers matches validation code
- Command field restriction for JSON stdin format accurately documented
  - Sequential launch flag exists and works as documented
- **CLI Flags** - All documented flags exist and match actual
implementation
- **Docker Configuration Examples** - Format and field names match
actual usage
- **Configuration Validation** - Documented behavior matches
`internal/config/validation*.go`

## Tested Commands

All commands from CONTRIBUTING....

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #886
lpcox added a commit that referenced this pull request Feb 14, 2026
The Serena MCP container was missing the Python language server,
preventing Python code analysis despite having the Python runtime
installed. Only Go language support was functional.

## Changes

- **Dockerfile**: Added `python-lsp-server[all]` installation between
Serena and TypeScript language server setup

The container already had:
- Go support via `gopls`
- TypeScript/JavaScript support via `typescript-language-server`
- Startup script correctly configuring all three languages in
`.serena/project.yml`

Only the Python language server package was missing. The `[all]` extra
includes optional dependencies for full LSP functionality.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build1194592432/b279/launcher.test
/tmp/go-build1194592432/b279/launcher.test
-test.testlogfile=/tmp/go-build1194592432/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ternal/fips140/bigmod/nat_amd64.--gdwarf-5 HEAD x_amd64/compile
/tmp/apt-dpkg-in/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/vet
tar amd64/compile x_amd64/compile add go -v x_amd64/vet -f 4971347/b009/
es x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1194592432/b264/config.test
/tmp/go-build1194592432/b264/config.test
-test.testlogfile=/tmp/go-build1194592432/b264/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
zclWGwGwi ache/go/1.25.7/x64/pkg/tool/linu-o .util;
print(imp/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/vet
r/runc-log.json /usr/sbin/tar 06.o ortc�� 64/src/runtime/cgo go
x_amd64/compile -f - /usr/sbin/dpkg-d-unreachable=false x_amd64/compile`
(dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build1194592432/b279/launcher.test
/tmp/go-build1194592432/b279/launcher.test
-test.testlogfile=/tmp/go-build1194592432/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ternal/fips140/bigmod/nat_amd64.--gdwarf-5 HEAD x_amd64/compile
/tmp/apt-dpkg-in/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/vet
tar amd64/compile x_amd64/compile add go -v x_amd64/vet -f 4971347/b009/
es x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build1194592432/b279/launcher.test
/tmp/go-build1194592432/b279/launcher.test
-test.testlogfile=/tmp/go-build1194592432/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ternal/fips140/bigmod/nat_amd64.--gdwarf-5 HEAD x_amd64/compile
/tmp/apt-dpkg-in/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/vet
tar amd64/compile x_amd64/compile add go -v x_amd64/vet -f 4971347/b009/
es x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1194592432/b288/mcp.test
/tmp/go-build1194592432/b288/mcp.test
-test.testlogfile=/tmp/go-build1194592432/b288/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
64/src/maps/iter.go ache/go/1.25.7/x64/pkg/tool/linu-o r/runc-log.json
abis /systemd-sysctl 08.o main�� ; then \
$GOPATH/bin/golangci-lint run --timeout=5m || echo &#34;��� Warning:
golangci-lint failed
/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/vet --auto
x_amd64/vet --detach 4971347/b004/ d-dispatcher/off-unreachable=false
x_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>[language-support] TypeScript/JavaScript and Python
language support not available in Serena MCP container</issue_title>
> <issue_description>## Summary
> 
> Testing of language support for Go, TypeScript/JavaScript, and Python
revealed that only **Go language support is working correctly**.
TypeScript/JavaScript and Python language servers are not available or
configured in the Serena MCP container.
> 
> ## Test Results
> 
> ### ✅ Go Language Support - PASSED
> 
> All Go language operations work correctly:
> - **Symbol overview**: Successfully retrieved functions and constants
from `main.go`
> - **Symbol finding**: Located `main` and `buildVersionString`
functions with detailed info
> - **Pattern search**: Found function declarations using regex patterns
> - **Reference finding**: Discovered all references to
`buildVersionString` across multiple files
> - **Code body retrieval**: Successfully retrieved complete function
implementations
> 
> ### ❌ TypeScript/JavaScript Language Support - FAILED
> 
> **Issue**: Cannot activate TypeScript/JavaScript projects
> - The Serena configuration (`.serena/project.yml`) only includes `go`
in the `languages:` list
> - Attempts to activate a JavaScript project failed with
`ProjectNotFoundError`
> - `tsserver` binary exists at `/usr/local/bin/tsserver` but no
TypeScript language server wrapper found
> - Configuration file is owned by root and cannot be modified due to
container security restrictions
> 
> ### ❌ Python Language Support - FAILED
> 
> **Issue**: Cannot activate Python projects
> - The Serena configuration (`.serena/project.yml`) only includes `go`
in the `languages:` list
> - Attempts to activate a Python project failed with
`ProjectNotFoundError`
> - No Python language servers found in the container (checked for
`pyls`, `pylsp`, `jedi-language-server`)
> - Configuration file permissions prevent adding Python to supported
languages
> 
> ## Root Cause
> 
> The Serena MCP container is configured with only Go language support.
The `.serena/project.yml` file contains:
> 
> ``````yaml
> languages:
> - go
> ``````
> 
> According to the project configuration documentation, supported
languages include:
> - `typescript` (also handles JavaScript files)
> - `python` (or `python_jedi` as alternative)
> 
> However, these are not enabled in the current configuration, and the
configuration file cannot be modified at runtime due to permission
restrictions.
> 
> ## Impact
> 
> - **Go projects**: ✅ Fully functional
> - **TypeScript/JavaScript projects**: ❌ Cannot be analyzed
> - **Python projects**: ❌ Cannot be analyzed
> - **Multi-language repositories**: Limited to Go code only
> 
> ## Reproduction Steps
> 
> 1. Start Serena MCP server with current configuration
> 2. Activate main Go project: `serena-activate_project` → **Success**
> 3. Try to activate TypeScript/JavaScript project:
`serena-activate_project` with JS path → **Fails with
ProjectNotFoundError**
> 4. Try to activate Python project: `serena-activate_project` with
Python path → **Fails with ProjectNotFoundError**
> 5. Check configuration: `cat .serena/project.yml` shows only `go` in
languages list
> 
> ## Recommendations
> 
> 1. **Update Serena container configuration** to include TypeScript and
Python language servers
> 2. **Modify `.serena/project.yml`** to include:
>    ``````yaml
>    languages:
>    - go
>    - typescript
>    - python
>    ``````
> 3. **Install required language servers** in the container:
>    - TypeScript: `typescript-language-server` or equivalent
>    - Python: `python-lsp-server` (pylsp) or `jedi-language-server`
> 4. **Test sample projects** at `test/serena-mcp-tests/samples/` once
language servers are available
> 
> ## Environment Details
> 
> - Repository: github/gh-aw-mcpg
> - Sparse checkout: 33% of files (Go code is present, test samples may
not be available)
> - Serena version: 0.1.4
> - Container: ghcr.io/github/serena-mcp-server:latest
> - Test date: 2026-02-12
> 
> 
> 
> 
> > AI generated by [Language Support
Tester](https://github.com/github/gh-aw-mcpg/actions/runs/21943451066)
> > - [x] expires <!-- gh-aw-expires: 2026-02-19T10:53:23.898Z --> on
Feb 19, 2026, 10:53 AM UTC
> 
> <!-- gh-aw-agentic-workflow: Language Support Tester, engine: copilot,
run: https://github.com/github/gh-aw-mcpg/actions/runs/21943451066 -->
> 
> <!-- gh-aw-workflow-id: language-support-tester
--></issue_description>
> 
> ## Comments on the Issue (you are @claude[agent] in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #913
lpcox added a commit that referenced this pull request Feb 16, 2026
…n() helper (#978)

Six MCP method wrappers (`listTools`, `callTool`, `listResources`,
`readResource`, `listPrompts`, `getPrompt`) contained identical 3-line
session nil checks, creating maintenance burden and risk of inconsistent
error messages.

## Changes

- **Extract validation helper**: Created `requireSession()` method to
centralize session nil checking
- **Update all callers**: Replaced inline checks across 6 methods with
helper call
- **Add test coverage**: Unit test validates helper behavior for nil
sessions

## Before/After

```go
// Before: Duplicated in 6 methods
func (c *Connection) listTools() (*Response, error) {
	if c.session == nil {
		return nil, fmt.Errorf("SDK session not available for plain JSON-RPC transport")
	}
	// ...
}

// After: Single source of truth
func (c *Connection) requireSession() error {
	if c.session == nil {
		return fmt.Errorf("SDK session not available for plain JSON-RPC transport")
	}
	return nil
}

func (c *Connection) listTools() (*Response, error) {
	if err := c.requireSession(); err != nil {
		return nil, err
	}
	// ...
}
```

Reduces code by ~12 lines and ensures consistent error messaging across
all SDK method wrappers.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build1651638344/b275/launcher.test
/tmp/go-build1651638344/b275/launcher.test
-test.testlogfile=/tmp/go-build1651638344/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true -c=4 -nolocalimports
-importcfg /tmp/go-build1651638344/b235/importcfg -pack
/home/REDACTED/go/pkg/mod/github.com/spf13/pflag@v1.0.9/bool.go
/home/REDACTED/go/pkg/mod/github.com/spf13/pflag@v1.0.9/bool_func.go
rev-�� go 8AG1CVhJp /home/REDACTED/wor-o wright&#34;
--viewpo/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/compile
5519/field .12/x64/git git` (dns block)
> - Triggering command: `/tmp/go-build4267259821/b275/launcher.test
/tmp/go-build4267259821/b275/launcher.test
-test.testlogfile=/tmp/go-build4267259821/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 1638344/b190/_pkg_.a
ache/go/1.25.7/x64/src/crypto/in-nolocalimports 1638344/b190=&gt; -p
l/ascii -lang=go1.25 /opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linu-I
go_.�� 64/src/net Wvey/P0HIK0znqdopQQs2Wvey x_amd64/compile -I ions =0
x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build4134285178/b275/launcher.test
/tmp/go-build4134285178/b275/launcher.test
-test.testlogfile=/tmp/go-build4134285178/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true se
1638344/b069/vet.cfg .cfg --gdwarf-5 --64 -o
ache/go/1.25.7/x64/pkg/tool/linux_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1651638344/b260/config.test
/tmp/go-build1651638344/b260/config.test
-test.testlogfile=/tmp/go-build1651638344/b260/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go
ternal/fips140/a--64 64/pkg/tool/linu-o nner/.nvm credential.helpe-I
/home/REDACTED/wor/opt/hostedtoolcache/go/1.25.7/x64/src/net
64/pkg/tool/linu-I rev-�� go HEAD x_amd64/vet list` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build1651638344/b275/launcher.test
/tmp/go-build1651638344/b275/launcher.test
-test.testlogfile=/tmp/go-build1651638344/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true -c=4 -nolocalimports
-importcfg /tmp/go-build1651638344/b235/importcfg -pack
/home/REDACTED/go/pkg/mod/github.com/spf13/pflag@v1.0.9/bool.go
/home/REDACTED/go/pkg/mod/github.com/spf13/pflag@v1.0.9/bool_func.go
rev-�� go 8AG1CVhJp /home/REDACTED/wor-o wright&#34;
--viewpo/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/compile
5519/field .12/x64/git git` (dns block)
> - Triggering command: `/tmp/go-build4267259821/b275/launcher.test
/tmp/go-build4267259821/b275/launcher.test
-test.testlogfile=/tmp/go-build4267259821/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 1638344/b190/_pkg_.a
ache/go/1.25.7/x64/src/crypto/in-nolocalimports 1638344/b190=&gt; -p
l/ascii -lang=go1.25 /opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linu-I
go_.�� 64/src/net Wvey/P0HIK0znqdopQQs2Wvey x_amd64/compile -I ions =0
x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build4134285178/b275/launcher.test
/tmp/go-build4134285178/b275/launcher.test
-test.testlogfile=/tmp/go-build4134285178/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true se
1638344/b069/vet.cfg .cfg --gdwarf-5 --64 -o
ache/go/1.25.7/x64/pkg/tool/linux_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build1651638344/b275/launcher.test
/tmp/go-build1651638344/b275/launcher.test
-test.testlogfile=/tmp/go-build1651638344/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true -c=4 -nolocalimports
-importcfg /tmp/go-build1651638344/b235/importcfg -pack
/home/REDACTED/go/pkg/mod/github.com/spf13/pflag@v1.0.9/bool.go
/home/REDACTED/go/pkg/mod/github.com/spf13/pflag@v1.0.9/bool_func.go
rev-�� go 8AG1CVhJp /home/REDACTED/wor-o wright&#34;
--viewpo/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/compile
5519/field .12/x64/git git` (dns block)
> - Triggering command: `/tmp/go-build4267259821/b275/launcher.test
/tmp/go-build4267259821/b275/launcher.test
-test.testlogfile=/tmp/go-build4267259821/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 1638344/b190/_pkg_.a
ache/go/1.25.7/x64/src/crypto/in-nolocalimports 1638344/b190=&gt; -p
l/ascii -lang=go1.25 /opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linu-I
go_.�� 64/src/net Wvey/P0HIK0znqdopQQs2Wvey x_amd64/compile -I ions =0
x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build4134285178/b275/launcher.test
/tmp/go-build4134285178/b275/launcher.test
-test.testlogfile=/tmp/go-build4134285178/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true se
1638344/b069/vet.cfg .cfg --gdwarf-5 --64 -o
ache/go/1.25.7/x64/pkg/tool/linux_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1651638344/b284/mcp.test
/tmp/go-build1651638344/b284/mcp.test
-test.testlogfile=/tmp/go-build1651638344/b284/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true in.so /lto-wrapper
/usr/bin/base64
WebFetch,WebSear/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/vet
a20 rgo/bin/git base64 ortc�� 64/src/runtime/c-errorsas 3-Nd5vpBC
ache/go/1.25.7/x-nilfunc --oneline -n /usr/bin/base64 04.o` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>


----

*This section details on the original issue you should resolve*

<issue_title>[duplicate-code] Duplicate Code Pattern: MCP Session Nil
Validation Checks</issue_title>
<issue_description># 🔍 Duplicate Code Pattern: MCP Session Validation
Checks

*Part of duplicate code analysis: #970*

## Summary

The `internal/mcp/connection.go` file contains **6 identical session nil
checks** across different MCP method wrappers. Each method performs the
exact same validation before executing its SDK call.

## Duplication Details

### Pattern: Repeated Session Nil Validation
- **Severity**: Medium
- **Occurrences**: 6 instances
- **Locations**:
  - `internal/mcp/connection.go`:
    - Line 821-823: `listTools()`
    - Line 833-835: `callTool()`
    - Line 867-869: `listResources()`
    - Line 879-881: `readResource()`
    - Line 901-903: `listPrompts()`
    - Line 913-915: `getPrompt()`

### Code Sample:
``````go
func (c *Connection) listTools() (*Response, error) {
	if c.session == nil {
		return nil, fmt.Errorf("SDK session not available for plain JSON-RPC transport")
	}
	result, err := c.session.ListTools(c.ctx, &sdk.ListToolsParams{})
	if err != nil {
		return nil, err
	}
	return marshalToResponse(result)
}

func (c *Connection) listResources() (*Response, error) {
	if c.session == nil {
		return nil, fmt.Errorf("SDK session not available for plain JSON-RPC transport")
	}
	result, err := c.session.ListResources(c.ctx, &sdk.ListResourcesParams{})
	if err != nil {
		return nil, err
	}
	return marshalToResponse(result)
}
// ... 4 more methods with identical session nil check
``````

## Impact Analysis

- **Maintainability**: **Medium Impact** - Error message changes require
updating 6 locations
- **Bug Risk**: **Medium** - Risk of inconsistent error messages if
updates are missed
- **Code Bloat**: ~18 lines of duplicate validation code (6 checks × 3
lines each)
- **Consistency**: Error messages could diverge over time if not
carefully maintained

## Refactoring Recommendations

### 1. **Extract Session Validation Helper** (Recommended)
Create a helper method to centralize the session validation:

``````go
// In connection.go
func (c *Connection) requireSession() error {
	if c.session == nil {
		return fmt.Errorf("SDK session not available for plain JSON-RPC transport")
	}
	return nil
}

// Updated methods use the helper:
func (c *Connection) listTools() (*Response, error) {
	if err := c.requireSession(); err != nil {
		return nil, err
	}
	result, err := c.session.ListTools(c.ctx, &sdk.ListToolsParams{})
	if err != nil {
		return nil, err
	}
	return marshalToResponse(result)
}

func (c *Connection) listResources() (*Response, error) {
	if err := c.requireSession(); err != nil {
		return nil, err
	}
	result, err := c.session.ListResources(c.ctx, &sdk.ListResourcesParams{})
	if err != nil {
		return nil, err
	}
	return marshalToResponse(result)
}
// ... other methods follow same pattern
``````

- **Location**: `internal/mcp/connection.go` (add `requireSession`
helper method)
- **Estimated Effort**: 1 hour
- **Benefits**:
  - Single point of truth for session validation
  - Consistent error messages across all methods
  - Easier to enhance validation logic (e.g., add logging, metrics)
  - Reduces code by ~12 lines

### 2. **Alternative: Method Decorator Pattern** (More Complex)
For a more sophisticated approach, consider a decorator that wraps SDK
calls:

``````go
type sdkCall func() (interface{}, error)

func (c *Connection) withSession(call sdkCall) (*Response, error) {
	if c.session == nil {
		return nil, fmt.Errorf("SDK session not available for plain JSON-RPC transport")
	}
	result, err := call()
	if err != nil {
		return nil, err
	}
	return marshalToResponse(result)
}

// Usage:
func (c *Connection) listTools() (*Response, error) {
	return c.withSession(func() (interface{}, error) {
		return c.session.ListTools(c.ctx, &sdk.ListToolsParams{})
	})
}
``````

- **Estimated Effort**: 2-3 hours
- **Benefits**: More DRY, but adds complexity with closures

## Implementation Checklist

- [ ] Review duplication findings
- [ ] Create `requireSession()` helper method in Connection struct
- [ ] Update `listTools()` to use helper
- [ ] Update `callTool()` to use helper
- [ ] Update `listResources()` to use helper
- [ ] Update `readResource()` to use helper
- [ ] Update `listPrompts()` to use helper
- [ ] Update `getPrompt()` to use helper
- [ ] Run `make test-all` to verify no functionality broken
- [ ] Run `make lint` to ensure code quality

## Parent Issue

See parent analysis report: #970
Related to #970




> AI generated by [Duplicate Code
Detector](https://github.com/github/gh-aw-mcpg/actions/runs/22058864442)
> - [x] expires <!-- gh-aw-expires: 2026-02-23T10:32:38.091Z --> on Feb
23, 2026, 10:32 AM UTC

<!-- gh-aw-agentic-workflow: Duplicate Code Detector, engine: copilot,
run: https://github.com/github/gh-aw-mcpg/actions/runs/22058864442 -->

<!-- gh-aw-workflow-id: ...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #972
lpcox added a commit that referenced this pull request Feb 16, 2026
The Go Fan report identified BurntSushi/toml as a critical dependency
and recommended verifying TOML 1.1 support, error reporting
improvements, and validation patterns. Analysis reveals the
implementation already follows all best practices—no functional changes
needed.

## Changes

**Enhanced inline documentation** (`internal/config/config_core.go`):
- Package-level overview of TOML 1.1 features (multi-line arrays,
duplicate key detection)
- Documented streaming decoder pattern and memory efficiency rationale
- Explained warning-based validation design decision (backward
compatibility vs strict errors)
- Clarified column-level error reporting (v1.5.0+ Position.Line +
Position.Col)

**Comprehensive review document** (`docs/TOML_MODULE_REVIEW.md`):
- Implementation analysis: TOML 1.1 specification support verified
- Multi-layer validation architecture documented (parse → schema →
field-level → variable expansion)
- Test coverage audit: 31+ tests including duplicate key detection,
streaming large files, unknown field warnings
- Best practices: MetaData.Undecoded() for typo detection, dual
type-check for ParseError compatibility

## Implementation Status

All Go Fan recommendations already implemented:
- ✅ TOML 1.1 compatibility (v1.6.0 default)
- ✅ Column-level error reporting with Position.Line and Position.Col
- ✅ Unknown field detection via MetaData.Undecoded() with warnings
- ✅ Streaming decoder for memory efficiency
- ✅ Comprehensive test coverage

## Example

Current error reporting with line and column numbers:

```go
if perr, ok := err.(*toml.ParseError); ok {
    return nil, fmt.Errorf("failed to parse TOML at line %d, column %d: %s",
        perr.Position.Line, perr.Position.Col, perr.Message)
}
```

TOML 1.1 multi-line arrays in use:

```toml
[servers.github]
args = [
    "run", "--rm", "-i",
    "--name", "awmg-github-mcp"
]
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build247104886/b279/launcher.test
/tmp/go-build247104886/b279/launcher.test
-test.testlogfile=/tmp/go-build247104886/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
HEAD 86_64/as toml k/gh-aw-mcpg/gh--unsafeptr=false
ache/Python/3.12-unreachable=false .o rev-�� go ac/hmac.go
x_amd64/compile toml 64975/b009/ /opt/hostedtoolc-unreachable=false
x_amd64/compile` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build247104886/b264/config.test
/tmp/go-build247104886/b264/config.test
-test.testlogfile=/tmp/go-build247104886/b264/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
64/src/unicode/casetables.go
ache/go/1.25.7/x64/pkg/tool/linux86_64-linux-gnu toml is rgo/bin/grep .o
rev-�� 64/src/runtime/cgo go x_amd64/compile toml
k/gh-aw-mcpg/gh--unsafeptr=false p/bin/grep x_amd64/compile` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build247104886/b279/launcher.test
/tmp/go-build247104886/b279/launcher.test
-test.testlogfile=/tmp/go-build247104886/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
HEAD 86_64/as toml k/gh-aw-mcpg/gh--unsafeptr=false
ache/Python/3.12-unreachable=false .o rev-�� go ac/hmac.go
x_amd64/compile toml 64975/b009/ /opt/hostedtoolc-unreachable=false
x_amd64/compile` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build247104886/b279/launcher.test
/tmp/go-build247104886/b279/launcher.test
-test.testlogfile=/tmp/go-build247104886/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
HEAD 86_64/as toml k/gh-aw-mcpg/gh--unsafeptr=false
ache/Python/3.12-unreachable=false .o rev-�� go ac/hmac.go
x_amd64/compile toml 64975/b009/ /opt/hostedtoolc-unreachable=false
x_amd64/compile` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build247104886/b288/mcp.test
/tmp/go-build247104886/b288/mcp.test
-test.testlogfile=/tmp/go-build247104886/b288/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
ternal/fips140/nistec/fiat/cast.--64 64/pkg/tool/linux_amd64/asm toml
k/gh-aw-mcpg/gh--unsafeptr=false k/_temp/ghcca-no-unreachable=false
64/pkg/tool/linu/tmp/go-build247104886/b068/vet.cfg -w ; then \
$GOPATH/bin/golangci-lint run --timeout=5m || echo &#34;��� Warning:
golangci-lint failed
/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/vet security
x_amd64/vet OUTPUT 64975/b004/ 168.63.129.16 x_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>


----

*This section details on the original issue you should resolve*

<issue_title>[go-fan] Go Module Review: BurntSushi/toml - TOML
Configuration Parser</issue_title>
<issue_description># 🐹 Go Fan Report: github.com/BurntSushi/toml

## Module Overview

**BurntSushi/toml** is the de-facto standard TOML parser for Go,
providing robust parsing and encoding of TOML configuration files with
full reflection support. It's the most popular and well-maintained TOML
library in the Go ecosystem, used by thousands of projects including the
MCP Gateway for parsing `config.toml` files.

- **Version**: v1.6.0 (latest, December 18, 2025)
- **Repository**: https://github.com/BurntSushi/toml
- **Stars**: 4,898 ⭐
- **License**: MIT
- **Maintainer**: Martin Tournoij (`@arp242`)
- **Last Update**: February 16, 2026 (updated just hours ago! 🔥)

## Current Usage in gh-aw-mcpg

**Note**: Analysis based on configuration files and documented patterns,
as the source code is not available in the sparse checkout.

### Configuration Files
- `config.toml` - Main gateway configuration
- `config.example.toml` - Comprehensive example (154 lines)
- `config.example-payload-threshold.toml` - Payload configuration

### Key Configuration Elements

The gateway uses TOML for:

1. **Gateway Settings** - Port, API key, timeouts, payload directory
2. **MCP Server Definitions** - Docker container configurations with:
   - Command and arguments arrays
   - Environment variable mappings
   - Tool filtering lists
3. **Modern TOML 1.1 Syntax** - Multi-line inline arrays, nested tables

### Example Configuration Pattern
``````toml
[gateway]
port = 3000
startup_timeout = 60
tool_timeout = 120

[servers.github]
command = "docker"
args = [
    "run", "--rm", "-i",
    "--name", "awmg-github-mcp",
    "-e", "GITHUB_PERSONAL_ACCESS_TOKEN"
]

[servers.github.env]
GITHUB_PERSONAL_ACCESS_TOKEN = ""
``````

## Research Findings

### 🔥 Recent Updates (Just Released Hours Ago!)

The repository was updated **today** (February 16, 2026) at 04:57 UTC,
making it an excellent time to review!

### Latest Version: v1.6.0 (December 18, 2025)

🎉 **Major Update**: **TOML 1.1 is now the default!**

**Key Changes**:
1. ✨ **TOML 1.1 Default** - Newlines in inline tables now allowed (huge
usability improvement!)
2. 🐛 **Fixed Duplicate Array Detection** - Now correctly detects
duplicate array keys as errors
3. 🔧 **Float Encoding** - Large floats round-trip correctly with
exponent syntax (e.g., `5e+22`)

**This is perfect timing!** The gateway's configs already use TOML 1.1
syntax with multi-line arrays, which is exactly what v1.6.0 enables by
default.

### Previous Versions

**v1.5.0 (March 18, 2025)**:
- Added `Position.Col` for **column-level error reporting** (line AND
column!)
- Allow custom string types as map keys
- Enhanced `ParseError.Message` to always be set
- Multiple encoding bug fixes

**v1.4.0 (May 23, 2024)**:
- **Added `toml.Marshal()`** - Convenient marshaling function
- Requires Go 1.18+
- Improved error position wrapping for custom types

### Best Practices from Module Documentation

1. **Detailed Error Handling**:
   ``````go
   var config Config
   meta, err := toml.DecodeFile("config.toml", &config)
   if err != nil {
       // ParseError includes line/column info
       log.Fatalf("Config error: %v", err)
   }
   ``````

2. **Strict Decoding** (Catch Typos):
   ``````go
   dec := toml.NewDecoder(file)
   dec.DisallowUnknownFields() // Errors on "prot" instead of "port"
   if err := dec.Decode(&config); err != nil {
       return fmt.Errorf("invalid config: %w", err)
   }
   ``````

3. **Metadata for Validation**:
   ``````go
   meta, _ := toml.Decode(data, &config)
   if !meta.IsDefined("required_field") {
       return errors.New("missing required field")
   }
   // Check for unrecognized keys
   if undecoded := meta.Undecoded(); len(undecoded) > 0 {
       log.Warnf("Unknown config keys: %v", undecoded)
   }
   ``````

4. **Marshal for Output**:
   ``````go
   data, err := toml.Marshal(config)
   if err != nil {
       return err
   }
   ``````

## Improvement Opportunities

**Important Note**: These recommendations are based on the module's
capabilities and common patterns. Implementation requires accessing the
full repository source code (currently unavailable due to sparse
checkout).

### 🏃 Quick Wins

#### 1. Verify TOML 1.1 Compatibility ✅
**Impact**: Low (already working) | **Effort**: Very Low

The gateway configs use TOML 1.1 syntax (multi-line arrays), which is
perfect since v1.6.0 makes it the default.

**Action**: 
- Verify no `BURNTSUSHI_TOML_110` environment variable workarounds in
code
- Confirm clean usage of TOML 1.1 features

**Benefit**: Ensure idiomatic usage of the latest TOML spec

#### 2. Leverage Enhanced Error Reporting (v1.5.0 Feature)
**Impact**: Medium | **Effort**: Low

v1.5.0 added `Position.Col` for column-level errors.

**Action**:
- Update error messages to show both line AND column: `"error at line
%d, column %d"`
- Th...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #969
lpcox added a commit that referenced this pull request Feb 19, 2026
The jq middleware payload preview size (500 characters) was hardcoded in
multiple locations, making it difficult to adjust consistently.

## Changes

- **Added `PayloadPreviewSize` constant** in
`internal/middleware/jqschema.go`
  - Replaces hardcoded `500` in preview truncation logic
  - Replaces hardcoded `500` in logging statements
  - Updates function documentation

- **Updated references** in documentation (`README.md`, `AGENTS.md`) and
tests to reference the constant

## Example

Before:
```go
truncated := len(payloadStr) > 500
if truncated {
    preview = payloadStr[:500] + "..."
}
```

After:
```go
truncated := len(payloadStr) > PayloadPreviewSize
if truncated {
    preview = payloadStr[:PayloadPreviewSize] + "..."
}
```

The constant provides a single point of configuration for payload
preview behavior across the middleware package.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build3360590955/b279/launcher.test
/tmp/go-build3360590955/b279/launcher.test
-test.testlogfile=/tmp/go-build3360590955/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 4047529/b162/_pkg_.a
64/src/runtime/cgo x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3360590955/b264/config.test
/tmp/go-build3360590955/b264/config.test
-test.testlogfile=/tmp/go-build3360590955/b264/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
3E2y/lfIxJsLvVk-kDynw3E2y .12/x64/bin/as` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build3360590955/b279/launcher.test
/tmp/go-build3360590955/b279/launcher.test
-test.testlogfile=/tmp/go-build3360590955/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 4047529/b162/_pkg_.a
64/src/runtime/cgo x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build3360590955/b279/launcher.test
/tmp/go-build3360590955/b279/launcher.test
-test.testlogfile=/tmp/go-build3360590955/b279/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 4047529/b162/_pkg_.a
64/src/runtime/cgo x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3360590955/b288/mcp.test
/tmp/go-build3360590955/b288/mcp.test
-test.testlogfile=/tmp/go-build3360590955/b288/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true se
4047529/b025/vet.cfg rgo/bin/as -p internal/msan -lang=go1.25
/opt/hostedtoolcache/go/1.25.7/x-trimpath go_.��
lcache/go/1.25.7/x64=/_/GOROOT Rd x_amd64/vet -p hash/maphash
-lang=go1.25 x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build1404549538/b001/mcp.test
/tmp/go-build1404549538/b001/mcp.test
-test.testlogfile=/tmp/go-build1404549538/b001/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -tes��
io.containerd.runtime.v2.task/moby/63201cdb6593143a21722511515a1/run/containerd/io.containerd.rugofmt
-test.timeout=10m0s k/gh-aw-mcpg/gh-aw-mcpg/awmg se
4047529/b025/vet--norc ffbfb0094a8a3294--noprofile
k/gh-aw-mcpg/gh-aw-mcpg/awmg -tes�� -test.paniconexit0 y
by/71af78b18fce5832ab10e180bbc3a77cfee5908e386c9517dcf943eeea458c34/log.json
ntime.v2.task/mo/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/vet
Rd t&#34;,
              &#34;REQUESTS_CA_B-c iginal` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.
lpcox added a commit that referenced this pull request Feb 19, 2026
The Language Support Tester workflow failed because it referenced the
registry image `ghcr.io/github/gh-aw-mcpg` without building it locally
first, causing Docker daemon connectivity issues and missing Serena MCP
tools.

## Changes

Added local container build steps following the `smoke-copilot.md`
pattern:

- **Docker Buildx setup** - Added `docker/setup-buildx-action@v3` step
- **Local MCP Gateway build** - Builds `local-awmg:v0.1.4` with embedded
`awmg` binary
- **Container reference** - Updated `sandbox.mcp.container` from
`ghcr.io/github/gh-aw-mcpg` to `local-awmg`

```yaml
steps:
  - name: Set up Docker Buildx
    uses: docker/setup-buildx-action@v3
  - name: Build local MCP Gateway container
    run: |
      VERSION="dev-$(git rev-parse --short HEAD)"
      docker build -t local-awmg:v0.1.4 --build-arg VERSION=${VERSION} .

sandbox:
  mcp:
    container: "local-awmg"  # Changed from registry reference
```

This ensures the MCP Gateway is available without external registry
dependencies, enabling Serena tools (`activate_project`, `find_symbols`,
etc.) for Go, TypeScript/JavaScript, and Python language testing.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> -
`https://api.github.com/repos/docker/setup-buildx-action/git/ref/tags/v3`
> - Triggering command: `/usr/bin/gh gh api
/repos/docker/setup-buildx-action/git/ref/tags/v3 --jq .object.sha`
(http block)
> - `https://api.github.com/repos/github/gh-aw/git/ref/tags/v0.46.1`
> - Triggering command: `/usr/bin/gh gh api
/repos/github/gh-aw/git/ref/tags/v0.46.1 --jq .object.sha` (http block)
> - `https://api.github.com/user`
> - Triggering command: `/usr/bin/gh gh api user --jq .login
-main/dist/indexuser.name` (http block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>[language-support] Serena MCP server tools unavailable —
language support tests could not run</issue_title>
> <issue_description>## Summary
> 
> The Language Support Tester workflow (run #34, run ID
22164360544) could not complete language support testing for **Go**,
**TypeScript/JavaScript**, and **Python** because the Serena MCP server
tools were not available in the sandbox environment.
> 
> ## Failure Details
> 
> ### Root Cause
> 
> The Docker daemon is not accessible from within the sandbox container:
> 
> ```
> Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is
the docker daemon running?
> ```
> 
> Because Docker is unavailable, the Serena MCP server container
(`ghcr.io/github/serena-mcp-server:latest`) cannot be started. As a
result, none of the language server tools (`activate_project`,
`find_symbols`, `get_definition`, etc.) were present in the agent's
available tool list.
> 
> ### Diagnostic evidence
> 
> - `/tmp/gh-aw/mcp-logs/` — empty (no MCP server logs, no `tools.json`)
> - `/tmp/gh-aw/mcp-config/` — contains only `jq-error.log`, no MCP
configuration JSON files
> - `docker images` / `docker ps` — command fails: daemon not reachable
> - `awmg` binary — not found in `PATH`
> - Serena tools (`activate_project`, `find_symbols`, etc.) — absent
from agent function-call interface
> 
> ### Languages affected
> 
> | Language | Status |
> |---|---|
> | Go | ❌ Not tested — Serena unavailable |
> | TypeScript/JavaScript | ❌ Not tested — Serena unavailable |
> | Python | ❌ Not tested — Serena unavailable |
> 
> ## Steps to Reproduce
> 
> 1. Trigger the **Language Support Tester** workflow
> 2. Observe that no Serena MCP tools appear in the agent's available
tools
> 3. `docker ps` inside the sandbox returns a daemon connection error
> 
> ## Expected Behavior
> 
> - Serena MCP server starts successfully
> - `activate_project`, `find_symbols`, `get_definition` tools are
available
> - Language support is verified for Go, TypeScript/JavaScript, and
Python
> 
> ## Suggested Investigation
> 
> - Verify that the sandbox container has access to the Docker daemon
(Docker-in-Docker or DooD)
> - Confirm the workflow's `tools: serena:` configuration is correctly
translating into MCP server setup
> - Check whether the pre-pull step (`docker pull
ghcr.io/github/serena-mcp-server:latest`) is succeeding before the agent
starts
> 
> 
> 
> 
> > Generated by [Language Support
Tester](https://github.com/github/gh-aw-mcpg/actions/runs/22164360544)
> > - [x] expires <!-- gh-aw-expires: 2026-02-26T01:14:02.300Z --> on
Feb 26, 2026, 1:14 AM UTC
> 
> <!-- gh-aw-agentic-workflow: Language Support Tester, engine: copilot,
run: https://github.com/github/gh-aw-mcpg/actions/runs/22164360544 -->
> 
> <!-- gh-aw-workflow-id: language-support-tester
--></issue_description>
> 
> ## Comments on the Issue (you are @copilot in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #1088

<!-- START COPILOT CODING AGENT TIPS -->
---

🔒 GitHub Advanced Security automatically protects Copilot coding agent
pull requests. You can protect all pull requests by enabling Advanced
Security for your repositories. [Learn more about Advanced
Security.](https://gh.io/cca-advanced-security)
lpcox added a commit that referenced this pull request Feb 23, 2026
…ddleware chaining code (#1311)

## Summary

Consolidates duplicate middleware chaining pattern (`WithSDKLogging` →
`rejectIfShutdown` → `applyAuthIfConfigured`) that was replicated
verbatim between `CreateHTTPServerForMCP` (transport.go) and
`CreateHTTPServerForRoutedMode` (routed.go).

## Changes

- **Added `wrapWithMiddleware` helper** in `http_helpers.go` that
encapsulates the standard middleware stack with documented spec
references (5.1.3 for shutdown, 7.1 for auth)
- **Updated both server factories** to use the helper, reducing 9 lines
of duplicate code per location to a single function call
- **Added comprehensive tests** covering auth scenarios, shutdown
behavior, middleware ordering verification, and log tag variations

## Example

Before:
```go
// Duplicated in both transport.go and routed.go
loggedHandler := WithSDKLogging(handler, "unified")
shutdownHandler := rejectIfShutdown(unifiedServer, loggedHandler, "server:transport")
finalHandler := applyAuthIfConfigured(apiKey, shutdownHandler.ServeHTTP)
```

After:
```go
// Single call, consistent across both modes
finalHandler := wrapWithMiddleware(handler, "unified", unifiedServer, apiKey)
```

## Impact

Adding new middleware layers (rate limiting, tracing, etc.) now requires
changes in one location instead of two, with spec references and
ordering documented centrally.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build1187723181/b275/launcher.test
/tmp/go-build1187723181/b275/launcher.test
-test.testlogfile=/tmp/go-build1187723181/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go HEAD ndor/bin/as
--global r = get &amp;&amp; echo &#34;--abbrev-ref ortcfg rev-��
64/src/runtime/c-c=4 64/src/os/dir_un-nolocalimports x_amd64/vet get
--global
ache/Python/3.12/home/REDACTED/go/pkg/mod/github.com/google/jsonschema-go@v0.4.2/jsonschema/annotations.go
x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1187723181/b260/config.test
/tmp/go-build1187723181/b260/config.test
-test.testlogfile=/tmp/go-build1187723181/b260/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true ortcfg s.go
64/pkg/tool/linu-o --global go x86-64.so.2 64/pkg/tool/linu-buildtags
ortc�� 1554416/b013/_pk-errorsas 64/src/crypto/in-ifaceassert
64/pkg/tool/linu-nilfunc unset --global 86_64/uname
64/pkg/tool/linu-tests` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build1187723181/b275/launcher.test
/tmp/go-build1187723181/b275/launcher.test
-test.testlogfile=/tmp/go-build1187723181/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go HEAD ndor/bin/as
--global r = get &amp;&amp; echo &#34;--abbrev-ref ortcfg rev-��
64/src/runtime/c-c=4 64/src/os/dir_un-nolocalimports x_amd64/vet get
--global
ache/Python/3.12/home/REDACTED/go/pkg/mod/github.com/google/jsonschema-go@v0.4.2/jsonschema/annotations.go
x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build1187723181/b275/launcher.test
/tmp/go-build1187723181/b275/launcher.test
-test.testlogfile=/tmp/go-build1187723181/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go HEAD ndor/bin/as
--global r = get &amp;&amp; echo &#34;--abbrev-ref ortcfg rev-��
64/src/runtime/c-c=4 64/src/os/dir_un-nolocalimports x_amd64/vet get
--global
ache/Python/3.12/home/REDACTED/go/pkg/mod/github.com/google/jsonschema-go@v0.4.2/jsonschema/annotations.go
x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1187723181/b284/mcp.test
/tmp/go-build1187723181/b284/mcp.test
-test.testlogfile=/tmp/go-build1187723181/b284/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go
64/src/internal/-ifaceassert 64/pkg/tool/linu-nilfunc --global
user.email ache/Python/3.12--abbrev-ref 64/pkg/tool/linuHEAD abis��
toml@v1.6.0/decode.go toml@v1.6.0/deprecated.go u/13/cc1 -tree /cgroup
k/_temp/ghcca-node/node/bin/node/opt/hostedtoolcache/go/1.25.6/x64/src/net
u/13/cc1` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>[duplicate-code] Duplicate Code Pattern: Middleware
Chaining and HTTP Server Construction</issue_title>
> <issue_description>*Part of duplicate code analysis:
#1283*
> 
> ## Summary
> 
> The three-step middleware wrapping chain (`WithSDKLogging` →
`rejectIfShutdown` → `applyAuthIfConfigured`) and the final
`http.Server` construction are duplicated verbatim between
`CreateHTTPServerForMCP` (transport.go) and
`CreateHTTPServerForRoutedMode` (routed.go), along with identical
comments.
> 
> ## Duplication Details
> 
> ### Pattern: Middleware chain + http.Server construction
> - **Severity**: Low
> - **Occurrences**: 2 (one per HTTP server factory function)
> - **Locations**:
>   - `internal/server/transport.go` (lines 118–135)
> - `internal/server/routed.go` (lines 140–162, inside per-backend loop)
> 
> **`transport.go`**:
> ````go
> // Wrap SDK handler with detailed logging for JSON-RPC translation
debugging
> loggedHandler := WithSDKLogging(streamableHandler, "unified")
> 
> // Apply shutdown check middleware (spec 5.1.3)
> // This must come before auth to ensure shutdown takes precedence
> shutdownHandler := rejectIfShutdown(unifiedServer, loggedHandler,
"server:transport")
> 
> // Apply auth middleware if API key is configured (spec 7.1)
> finalHandler := applyAuthIfConfigured(apiKey,
shutdownHandler.ServeHTTP)
> 
> mux.Handle("/mcp/", finalHandler)
> mux.Handle("/mcp", finalHandler)
> 
> return &http.Server{Addr: addr, Handler: mux}
> ````
> 
> **`routed.go`** (inside per-backend loop, then after):
> ````go
> loggedHandler := WithSDKLogging(routeHandler, "routed:"+backendID)
> shutdownHandler := rejectIfShutdown(unifiedServer, loggedHandler,
"server:routed")
> finalHandler := applyAuthIfConfigured(apiKey,
shutdownHandler.ServeHTTP)
> 
> mux.Handle(route+"/", finalHandler)
> mux.Handle(route, finalHandler)
> 
> // ... (outside loop)
> return &http.Server{Addr: addr, Handler: mux}
> ````
> 
> ## Impact Analysis
> 
> - **Maintainability**: Adding a new middleware layer (e.g., rate
limiting, tracing) requires changes in both files. The spec references
in comments (5.1.3, 7.1) would also need to be kept in sync.
> - **Bug Risk**: Low, since the middleware order is mechanically
enforced, but adding middleware only in one place is a realistic
mistake.
> - **Code Bloat**: Minor (~6 lines duplicated).
> 
> ## Refactoring Recommendations
> 
> 1. **Extract a `wrapWithMiddleware` helper** in `transport.go` or
`http_helpers.go`:
>    ````go
> // wrapWithMiddleware applies the standard middleware stack to an SDK
handler.
> // Order: SDK logging → shutdown check (spec 5.1.3) → auth (spec 7.1)
> func wrapWithMiddleware(handler http.Handler, logTag string,
unifiedServer *UnifiedServer, apiKey string) http.HandlerFunc {
>        loggedHandler := WithSDKLogging(handler, logTag)
> shutdownHandler := rejectIfShutdown(unifiedServer, loggedHandler,
"server:"+logTag)
>        return applyAuthIfConfigured(apiKey, shutdownHandler.ServeHTTP)
>    }
>    ````
> 
> 2. **Optionally extract `buildHTTPServer`**:
>    ````go
> func buildHTTPServer(addr string, mux *http.ServeMux) *http.Server {
>        return &http.Server{Addr: addr, Handler: mux}
>    }
>    ````
> 
> 3. **Estimated effort**: ~20 minutes  
> 4. **Benefits**: Middleware order documented and enforced in one
place; easier to add new middleware globally
> 
> ## Implementation Checklist
> 
> - [ ] Review duplication findings
> - [ ] Extract `wrapWithMiddleware` helper
> - [ ] Update `transport.go` and `routed.go` to use the helper
> - [ ] Verify middleware order is preserved
> - [ ] Verify no functionality broken
> 
> ## Parent Issue
> 
> See parent analysis report: #1283
> Related to #1283
> 
> 
> 
> 
> > Generated by [Duplicate Code
Detector](https://github.com/github/gh-aw-mcpg/actions/runs/22269224479)
> > - [x] expires <!-- gh-aw-expires: 2026-03-01T03:02:48.820Z --> on
Mar 1, 2026, 3:02 AM UTC
> 
> <!-- gh-aw-agentic-workflow: Duplicate Code Detector, engine: copilot,
run: https://github.com/github/gh-aw-mcpg/actions/runs/22269224479 -->
> 
> <!-- gh-aw-workflow-id: duplicate-code-detector
--></issue_description>
> 
> ## Comments on the Issue (you are @claude[agent] in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #1284
lpcox added a commit that referenced this pull request Feb 23, 2026
The language-support-tester workflow was failing at runtime because
Serena MCP tools (`serena-get_symbols_overview`, `serena-find_symbol`)
were unavailable, blocking Go, TypeScript, and Python language support
tests.

## Root Cause

The `.lock.yml` file was compiled with gh-aw v0.48.3 and out of sync
with its source. The workflow needed recompilation to pick up:

- MCP gateway upgrade (v0.1.4 → v0.1.5)
- Compiler improvements (v0.48.3 → v0.49.2)
- Updated prompt handling

## Changes

- Recompiled `.github/workflows/language-support-tester.lock.yml` using
`gh aw compile`
- Updated compiler metadata and dependency versions

## Configuration Verification

The source `.md` file was already correct:
- Serena tool specification: `serena: ["go", "typescript", "python"]`
(array format) ✓
- Container config: `ghcr.io/github/serena-mcp-server:latest` ✓
- Entrypoint: `start-mcp-server --context codex --project
${GITHUB_WORKSPACE}` ✓
- Test samples present for all three languages ✓

Serena tools should now be available when the workflow runs.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build546163221/b275/launcher.test
/tmp/go-build546163221/b275/launcher.test
-test.testlogfile=/tmp/go-build546163221/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go1.25.6 -c=4
-nolocalimports -importcfg /tmp/go-build546163221/b160/importcfg -pack
/opt/hostedtoolcache/go/1.25.6/x64/src/crypto/x509/cert_pool.go rev-��
go HEAD /usr/bin/base64 it base64
ache/Python/3.12/tmp/go-build546163221/b182/_pkg_.a 64/pkg/include` (dns
block)
> - `https://api.github.com/repos/actions/setup-go/git/ref/tags/v6`
> - Triggering command: `/usr/bin/gh gh api
/repos/actions/setup-go/git/ref/tags/v6 --jq .object.sha
/home/REDACTED/.cargo/bin/git base64 tnet/tools/git /usr/bin/base64 git
/usr/local/.ghcup/bin/git base64 -d t git ndor/bin/git 0,
length(NVM_DIbase64 HEAD bin/git git` (http block)
> -
`https://api.github.com/repos/docker/setup-buildx-action/git/ref/tags/v3`
> - Triggering command: `/usr/bin/gh gh api
/repos/docker/setup-buildx-action/git/ref/tags/v3 --jq .object.sha`
(http block)
> - Triggering command: `/usr/bin/gh gh api
/repos/docker/setup-buildx-action/git/ref/tags/v3 --jq .object.sha
/home/REDACTED/.lo/home/REDACTED/.nvm/Dockerfile base64 cal/bin/git
/usr/bin/base64 with v0.49.2).
-20 /usr/bin/sed base64 -d .12/x64/git sed
/home/REDACTED/.lo/home/REDACTED/.nvm/nvm-exec s/^session\.savebase64
ons/[^/]*)?/[^/]-d /) exit(2);
    /home/REDACTED/.nvm/rename_test.sh git` (http block)
> - `https://api.github.com/repos/github/gh-aw/git/ref/tags/v0.49.2`
> - Triggering command: `/usr/bin/gh gh api
/repos/github/gh-aw/git/ref/tags/v0.49.2 --jq .object.sha ndor/bin/git
git /usr/bin/base64 --abbrev-ref HEAD /usr/bin/base64 base64 -d
/usr/bin/awk base64 /usr/bin/base64 /g awk /usr/bin/which t }
  }
  { printf &#34;%s%s&#34;, sep, HEAD` (http block)
> - Triggering command: `/usr/bin/gh gh api
/repos/github/gh-aw/git/ref/tags/v0.49.2 --jq .object.sha
/usr/local/.ghcup/bin/git base64 it /usr/bin/base64 git ndor/bin/git
base64 -d nfig/composer/vendor/bin/git git /snap/bin/git --abbrev-ref
HEAD ache/uv/0.10.4/x86_64/git git` (http block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build546163221/b260/config.test
/tmp/go-build546163221/b260/config.test
-test.testlogfile=/tmp/go-build546163221/b260/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go
ternal/fips140/a--gdwarf2 64/pkg/tool/linu--64 ^/home/REDACTED/.nas git
/usr/bin/base64 64/pkg/tool/linu-I rev-�� go lang.org/x/text/--64
64/pkg/tool/linu-o
nfig/composer/ve/opt/hostedtoolcache/go/1.25.6/x64/pkg/tool/linux_amd64/vet
base64 bin/git 64/pkg/tool/linu/tmp/go-build546163221/b193/vet.cfg` (dns
block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build546163221/b275/launcher.test
/tmp/go-build546163221/b275/launcher.test
-test.testlogfile=/tmp/go-build546163221/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go1.25.6 -c=4
-nolocalimports -importcfg /tmp/go-build546163221/b160/importcfg -pack
/opt/hostedtoolcache/go/1.25.6/x64/src/crypto/x509/cert_pool.go rev-��
go HEAD /usr/bin/base64 it base64
ache/Python/3.12/tmp/go-build546163221/b182/_pkg_.a 64/pkg/include` (dns
block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build546163221/b275/launcher.test
/tmp/go-build546163221/b275/launcher.test
-test.testlogfile=/tmp/go-build546163221/b275/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go1.25.6 -c=4
-nolocalimports -importcfg /tmp/go-build546163221/b160/importcfg -pack
/opt/hostedtoolcache/go/1.25.6/x64/src/crypto/x509/cert_pool.go rev-��
go HEAD /usr/bin/base64 it base64
ache/Python/3.12/tmp/go-build546163221/b182/_pkg_.a 64/pkg/include` (dns
block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build546163221/b284/mcp.test
/tmp/go-build546163221/b284/mcp.test
-test.testlogfile=/tmp/go-build546163221/b284/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true _.a HEAD
64/pkg/tool/linux_amd64/compile de/node/bin/git tail /) exit(2);
-unreachable=false 64/pkg/tool/linu/tmp/go-build546163221/b120/vet.cfg
/hom�� go Usv7CWTeK x_amd64/vet bin/git base64 /usr/bin/head
x_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> 
> ----
> 
> *This section details on the original issue you should resolve*
> 
> <issue_title>[language-support] Serena MCP tools unavailable —
language support testing blocked (Go, TypeScript/JavaScript,
Python)</issue_title>
> <issue_description>## Summary
> 
> The automated language support tester ran and attempted to test Go,
TypeScript/JavaScript, and Python language support using the Serena MCP
server. All three tests failed because the required Serena MCP tools are
not available in the agent's tool inventory.
> 
> ## Failed Tests
> 
> | Language | Tool Attempted | Result |
> |----------|---------------|--------|
> | Go | `serena-get_symbols_overview` (relative_path:
`internal/server`) | ❌ Tool not available |
> | Go | `serena-find_symbol` | ❌ Tool not available |
> | TypeScript/JavaScript | `serena-get_symbols_overview`
(relative_path:
`test/serena-mcp-tests/samples/js_project/calculator.js`) | ❌ Tool not
available |
> | TypeScript/JavaScript | `serena-find_symbol` | ❌ Tool not available
|
> | Python | `serena-get_symbols_overview` (relative_path:
`test/serena-mcp-tests/samples/python_project/calculator.py`) | ❌ Tool
not available |
> | Python | `serena-find_symbol` | ❌ Tool not available |
> 
> ## Error Details
> 
> When the agent attempted to call `serena-get_symbols_overview` and
`serena-find_symbol`, neither tool appeared in the available tool set.
The Serena MCP server does not appear to be running and connected as an
MCP server in this workflow environment.
> 
> ## Steps to Reproduce
> 
> 1. Trigger the `language-support-tester` workflow
> 2. Observe that `serena-get_symbols_overview` and `serena-find_symbol`
are not listed as available tools
> 3. All Serena-based language tests fail
> 
> ## Expected Behavior
> 
> The Serena MCP server should be running and its tools should be
available with the `serena-` prefix, as documented in
`.github/agentics/language-support-tester.md`.
> 
> ## Possible Causes
> 
> - The Serena MCP server is not configured or not started in this
workflow
> - The MCP gateway is not routing Serena tool calls correctly
> - The `serena` tool configuration in the workflow definition may be
missing or incorrect (should use array format: `serena: ["go",
"typescript", "python"]`)
> 
> ## References
> 
> - Workflow definition: `.github/workflows/language-support-tester.md`
> - Agent prompt: `.github/agentics/language-support-tester.md`
> 
> 
> 
> 
> > Generated by [Language Support
Tester](https://github.com/github/gh-aw-mcpg/actions/runs/22292141786)
> > - [x] expires <!-- gh-aw-expires: 2026-03-02T03:49:03.671Z --> on
Mar 2, 2026, 3:49 AM UTC
> 
> <!-- gh-aw-agentic-workflow: Language Support Tester, engine: copilot,
run: https://github.com/github/gh-aw-mcpg/actions/runs/22292141786 -->
> 
> <!-- gh-aw-workflow-id: language-support-tester
--></issue_description>
> 
> ## Comments on the Issue (you are @claude[agent] in this section)
> 
> <comments>
> </comments>
> 


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes #1309
lpcox added a commit that referenced this pull request Mar 10, 2026
…cies exist (#1741)

The v0.1.12 auto-detection introduced a timing bug where guards were
downgraded to noop during registration, before DIFC auto-enablement ran.
This broke AllowOnly enforcement in smoke tests.

## Problem

Guard registration (line 180) happens before auto-detection (line 188).
When `requireGuardPolicyIfGuardEnabled` finds no resolved policy during
registration, it falls back to noop. By the time
`hasServerGuardPolicies(cfg)` triggers auto-enablement, the guard is
already noop.

## Solution

Modified `requireGuardPolicyIfGuardEnabled` to check
`serverCfg.GuardPolicies` before falling back:

```go
if policy == nil {
    // Keep non-noop guard if server has guard policies configured
    if serverCfg, ok := us.cfg.Servers[serverID]; ok && len(serverCfg.GuardPolicies) > 0 {
        return g, nil  // Guard will be initialized on first use
    }
    return guard.NewNoopGuard(), nil
}
```

This preserves the WASM guard discovered from `/guards/{serverID}/` when
guard policies exist, allowing proper initialization during
`ensureGuardInitialized`.

## Changes

- **internal/server/unified.go**: Added guard policy check before noop
fallback
- **internal/server/require_guard_policy_test.go**: Tests for fallback
behavior with/without policies
- **internal/server/guard_policy_parsing_test.go**: Tests for
`parseServerGuardPolicy` and `resolveGuardPolicy`
- **internal/server/has_server_guard_policies_test.go**: Tests for
policy detection logic

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build2269947796/b332/launcher.test
/tmp/go-build2269947796/b332/launcher.test
-test.testlogfile=/tmp/go-build2269947796/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true --abbrev-ref HEAD
/usr/bin/base64 --abbrev-ref 877973&#43;lpcox@userev-parse
ache/Python/3.12--abbrev-ref base64 -d 64/pkg/tool/linu--abbrev-ref
base64 /usr/bin/dirname x_amd64/compile 64/pkg/tool/linu-d ndor/bin/git
t }
  }
  { printf &#34;%s%s&#34;, sep, HEAD` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2269947796/b314/config.test
/tmp/go-build2269947796/b314/config.test
-test.testlogfile=/tmp/go-build2269947796/b314/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true --abbrev-ref HEAD
/usr/bin/base64 m/CLAUDE.md m/CODE_OF_CONDUC-o
ache/go/1.25.7/x/tmp/go-build1778197618/b062/_pkg_.a base64 -d
m/LICENSE.md m/Makefile /home/REDACTED/go/-lang=go1.25 m/README.md
m/ROADMAP.md Policy_ServerGuaccs13v1iKv05Y3GP5cax/ccs13v1iKv05Y3GP5cax
git` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build2269947796/b332/launcher.test
/tmp/go-build2269947796/b332/launcher.test
-test.testlogfile=/tmp/go-build2269947796/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true --abbrev-ref HEAD
/usr/bin/base64 --abbrev-ref 877973&#43;lpcox@userev-parse
ache/Python/3.12--abbrev-ref base64 -d 64/pkg/tool/linu--abbrev-ref
base64 /usr/bin/dirname x_amd64/compile 64/pkg/tool/linu-d ndor/bin/git
t }
  }
  { printf &#34;%s%s&#34;, sep, HEAD` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build2269947796/b332/launcher.test
/tmp/go-build2269947796/b332/launcher.test
-test.testlogfile=/tmp/go-build2269947796/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true --abbrev-ref HEAD
/usr/bin/base64 --abbrev-ref 877973&#43;lpcox@userev-parse
ache/Python/3.12--abbrev-ref base64 -d 64/pkg/tool/linu--abbrev-ref
base64 /usr/bin/dirname x_amd64/compile 64/pkg/tool/linu-d ndor/bin/git
t }
  }
  { printf &#34;%s%s&#34;, sep, HEAD` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2269947796/b341/mcp.test
/tmp/go-build2269947796/b341/mcp.test
-test.testlogfile=/tmp/go-build2269947796/b341/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true --abbrev-ref HEAD
ptables --abbrev-ref 877973&#43;lpcox@use-c tnet/tools/git base64` (dns
block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Mar 11, 2026
Addresses duplicate code analysis findings: ~60 lines of repeated
mutex-locking and logging patterns across logger and DIFC packages.

## Changes

**DIFC Tag Mutation (#1767)** - 21 lines reduced
- Extracted `modifyTag` helper to consolidate mutex-lock + dual-logging
pattern
- Refactored `AddSecrecyTag`, `AddIntegrityTag`, `DropIntegrityTag`

```go
// Before: duplicated 7-line pattern in each method
func (a *AgentLabels) AddSecrecyTag(tag Tag) {
    logAgent.Printf("Agent %s adding secrecy tag: %s", a.AgentID, tag)
    a.mu.Lock()
    defer a.mu.Unlock()
    a.Secrecy.Label.Add(tag)
    log.Printf("[DIFC] Agent %s gained secrecy tag: %s", a.AgentID, tag)
}

// After: unified helper
func (a *AgentLabels) AddSecrecyTag(tag Tag) {
    a.modifyTag("secrecy", "adding", "gained", tag, func() {
        a.Secrecy.Label.Add(tag)
    })
}
```

**Global Logger RWMutex Access (#1768)** - 40 lines reduced
- Created generic `withGlobalLogger` helper with `closableLogger`
constraint
- Refactored 8+ call sites across file_logger, markdown_logger,
jsonl_logger, server_file_logger, tools_logger, rpc_logger

```go
// Before: duplicated RWMutex pattern
globalLoggerMu.RLock()
defer globalLoggerMu.RUnlock()
if globalLogger != nil {
    globalLogger.DoSomething(args...)
}

// After: type-safe generic helper
withGlobalLogger(&globalLoggerMu, &globalLogger, func(logger *Logger) {
    logger.DoSomething(args...)
})
```

**Logger Initialization (#1766)** - No changes required
- Reviewed existing `initLogger` generic - already well-abstracted
- Documented pattern rationale in common.go

## Documentation
Added "Global Logger RWMutex Access Pattern" section to
`internal/logger/common.go` explaining the refactoring approach and
benefits.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build2039083650/b332/launcher.test
/tmp/go-build2039083650/b332/launcher.test
-test.testlogfile=/tmp/go-build2039083650/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true se stmain.go
ache/go/1.25.7/x64/pkg/tool/linux_amd64/link . --gdwarf2 --64
ache/go/1.25.7/x64/pkg/tool/linuHEAD -I 7410264/b320/difc.test -I
86_64/git --gdwarf-5 --64 -o
Rlvht1SmvPjlx/EgKV67uNxy1s5Sk4WJTJ/FFffmGA1P5hLrHEAD` (dns block)
> - Triggering command: `/tmp/go-build139309952/b332/launcher.test
/tmp/go-build139309952/b332/launcher.test
-test.testlogfile=/tmp/go-build139309952/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true .cfg
/opt/hostedtoolc-goversion 64/pkg/tool/linux_amd64/vet -bool -buildtags
ache/go/1.25.7/x/tmp/go-build139309952/b319/_pkg_.a
64/pkg/tool/linu-trimpath rev-�� .cfg HEAD ache/go/1.25.7/x-lang=go1.25
--abbrev-ref HEAD tnet/tools/git tf &#34;%s%s&#34;, sep, -goversion`
(dns block)
> - Triggering command: `/tmp/go-build311971124/b336/launcher.test
/tmp/go-build311971124/b336/launcher.test
-test.testlogfile=/tmp/go-build311971124/b336/testlog.txt
-test.paniconexit0 -test.timeout=10m0s star��` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2039083650/b314/config.test
/tmp/go-build2039083650/b314/config.test
-test.testlogfile=/tmp/go-build2039083650/b314/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 7410264/b253/_pkg_.a
/tmp/go-build1837410264/b068/vet.cfg
ache/go/1.25.7/x64/pkg/tool/linux_amd64/vet -dumpbase ntio/asm/base64
-dumpbase-ext ache/go/1.25.7/xHEAD eU_a��
/opt/hostedtoolcache/go/1.25.7/x64/src/net -I rgo/bin/git
7410264/b253/symbase64 --64 -o /opt/hostedtoolcache/go/1.25.7/xHEAD`
(dns block)
> - Triggering command: `/tmp/go-build139309952/b314/config.test
/tmp/go-build139309952/b314/config.test
-test.testlogfile=/tmp/go-build139309952/b314/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true ;
            s#^/home/REDACTED/.nvm/##;
            \#^[^v]# d;
            \#^versions$# d;
tr /opt/hostedtoolcache/go/1.25.7/xHEAD 64/pkg/tool/linux_amd64/vet
pkg/mod/github.cgit pkg/mod/github.crev-parse
ache/Python/3.12--abbrev-ref 64/pkg/tool/linuHEAD /usr�� .cfg
/opt/hostedtoolc-test.timeout=10m0s 64/pkg/tool/linux_amd64/vet
github.com/segmebase64 -trimpath .12/x64/git
64/pkg/tool/linux_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build311971124/b318/config.test
/tmp/go-build311971124/b318/config.test
-test.testlogfile=/tmp/go-build311971124/b318/testlog.txt
-test.paniconexit0 -test.timeout=10m0s .pro��
/opt/hostedtoolc--abbrev-ref /opt/hostedtoolcHEAD
d-dispatcher/off.d/chrony-onoffline /tmp/go-build186dirname git
64/pkg/tool/linux_amd64/compile d-dispatcher/off.d/chrony-onoffline
-nam�� moby -id /usr/bin/runc.original -address /run/containerd/-d
docker-buildx /usr/bin/runc.original` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build2039083650/b332/launcher.test
/tmp/go-build2039083650/b332/launcher.test
-test.testlogfile=/tmp/go-build2039083650/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true se stmain.go
ache/go/1.25.7/x64/pkg/tool/linux_amd64/link . --gdwarf2 --64
ache/go/1.25.7/x64/pkg/tool/linuHEAD -I 7410264/b320/difc.test -I
86_64/git --gdwarf-5 --64 -o
Rlvht1SmvPjlx/EgKV67uNxy1s5Sk4WJTJ/FFffmGA1P5hLrHEAD` (dns block)
> - Triggering command: `/tmp/go-build139309952/b332/launcher.test
/tmp/go-build139309952/b332/launcher.test
-test.testlogfile=/tmp/go-build139309952/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true .cfg
/opt/hostedtoolc-goversion 64/pkg/tool/linux_amd64/vet -bool -buildtags
ache/go/1.25.7/x/tmp/go-build139309952/b319/_pkg_.a
64/pkg/tool/linu-trimpath rev-�� .cfg HEAD ache/go/1.25.7/x-lang=go1.25
--abbrev-ref HEAD tnet/tools/git tf &#34;%s%s&#34;, sep, -goversion`
(dns block)
> - Triggering command: `/tmp/go-build311971124/b336/launcher.test
/tmp/go-build311971124/b336/launcher.test
-test.testlogfile=/tmp/go-build311971124/b336/testlog.txt
-test.paniconexit0 -test.timeout=10m0s star��` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build2039083650/b332/launcher.test
/tmp/go-build2039083650/b332/launcher.test
-test.testlogfile=/tmp/go-build2039083650/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true se stmain.go
ache/go/1.25.7/x64/pkg/tool/linux_amd64/link . --gdwarf2 --64
ache/go/1.25.7/x64/pkg/tool/linuHEAD -I 7410264/b320/difc.test -I
86_64/git --gdwarf-5 --64 -o
Rlvht1SmvPjlx/EgKV67uNxy1s5Sk4WJTJ/FFffmGA1P5hLrHEAD` (dns block)
> - Triggering command: `/tmp/go-build139309952/b332/launcher.test
/tmp/go-build139309952/b332/launcher.test
-test.testlogfile=/tmp/go-build139309952/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true .cfg
/opt/hostedtoolc-goversion 64/pkg/tool/linux_amd64/vet -bool -buildtags
ache/go/1.25.7/x/tmp/go-build139309952/b319/_pkg_.a
64/pkg/tool/linu-trimpath rev-�� .cfg HEAD ache/go/1.25.7/x-lang=go1.25
--abbrev-ref HEAD tnet/tools/git tf &#34;%s%s&#34;, sep, -goversion`
(dns block)
> - Triggering command: `/tmp/go-build311971124/b336/launcher.test
/tmp/go-build311971124/b336/launcher.test
-test.testlogfile=/tmp/go-build311971124/b336/testlog.txt
-test.paniconexit0 -test.timeout=10m0s star��` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2039083650/b341/mcp.test
/tmp/go-build2039083650/b341/mcp.test
-test.testlogfile=/tmp/go-build2039083650/b341/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
/opt/hostedtoolcache/go/1.25.7/x64/src/net -I iptables --gdwarf-5 --64
-o as -I /opt/hostedtoolcache/go/1.25.7/x64/src/net -I
7410264/b248/vet.cfg --gdwarf-5 --64 -o */bin.*$&#34;) { next }
  }
  { printf &#34;%s%s&#34;, sep, HEAD` (dns block)
> - Triggering command: `/tmp/go-build139309952/b341/mcp.test
/tmp/go-build139309952/b341/mcp.test
-test.testlogfile=/tmp/go-build139309952/b341/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true -importcfg
4E-sSYy/pwgIjRIG-w ache/go/1.25.7/x-buildmode=exe --abbrev-ref HEAD
nfig/composer/ve--version ache/go/1.25.7/x-extld=gcc` (dns block)
> - Triggering command: `/tmp/go-build311971124/b345/mcp.test
/tmp/go-build311971124/b345/mcp.test
-test.testlogfile=/tmp/go-build311971124/b345/testlog.txt
-test.paniconexit0 -test.timeout=10m0s /usr��
1dedc330cd146d1731f9c903fe295e422bb440808c4a20ae
/var/run/docker/runtime-runc/moby 86_64/git
/run/containerd//opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/vet
--log-format json 1a2fc60e6817294b-buildtags /usr�� --root
/var/run/docker/-ifaceassert by/7842e098fbefc-nilfunc
/run/containerd/bash 1a2fc60e6817294b/usr/bin/runc json
1a2fc60e6817294b-tests` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Mar 11, 2026
## Summary

Eliminates ~71 lines of duplicate code across the DIFC package by
extracting two generic helpers. Addresses issue #1719 patterns 2 and 3
(pattern 1 was previously resolved).

## Changes

### CheckFlow Consolidation (`labels.go`)

**Problem**: `SecrecyLabel.CheckFlow` and `IntegrityLabel.CheckFlow`
contained 58 lines of nearly identical nil handling, locking, and tag
iteration logic with only semantic differences (subset vs superset
checks).

**Solution**: Extracted `checkFlowHelper` that parameterizes flow
semantics:

```go
// Generic helper with parameterized semantics
func checkFlowHelper(srcLabel *Label, targetLabel *Label, checkSubset bool, labelType string) (bool, []Tag)

// Thin wrappers (10 lines each)
func (l *SecrecyLabel) CheckFlow(target *SecrecyLabel) (bool, []Tag) {
    return checkFlowHelper(l.Label, target.Label, true, "Secrecy")  // subset check
}

func (l *IntegrityLabel) CheckFlow(target *IntegrityLabel) (bool, []Tag) {
    return checkFlowHelper(l.Label, target.Label, false, "Integrity")  // superset check
}
```

### EvaluationResult Initialization (`evaluator.go`)

**Problem**: Three evaluation functions repeated identical 5-line
initialization blocks.

**Solution**: Extracted `newEmptyEvaluationResult()` helper used by
`Evaluate`, `evaluateRead`, and `evaluateWrite`.

## Testing

- Added 12 comprehensive test cases for new helpers
- All existing tests pass (100+ in difc package)
- No behavior changes

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build817523219/b332/launcher.test
/tmp/go-build817523219/b332/launcher.test
-test.testlogfile=/tmp/go-build817523219/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ache/go/1.25.7/x64/src/runtime/c-errorsas J4aB/2fPHF0HdMhn8ydxhJ4aB
64/pkg/tool/linux_amd64/vet -I /tmp/go-build151-n -I
64/pkg/tool/linux_amd64/vet go_.�� 8036719/b171=/tmp/go-build .cfg
64/pkg/tool/linux_amd64/vet -p ache/go/1.25.7/x-d -lang=go1.16
64/pkg/tool/linux_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build2582390263/b336/launcher.test
/tmp/go-build2582390263/b336/launcher.test
-test.testlogfile=/tmp/go-build2582390263/b336/testlog.txt
-test.paniconexit0 -test.timeout=10m0s [
�� --prefix=/net/ipv4/neigh/veth8c3e74e
--prefix=/net/ipv6/conf/veth8c3e74e ache/uv/0.10.9/x86_64/git --64
ache/go/1.25.7/x-d /snap/bin/git bash /usr�� --root
/var/run/docker/runtime-runc/moby 64/pkg/tool/linux_amd64/vet
/run/containerd/bash --log-format 619fd60bb04098d5--version
64/pkg/tool/linux_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build817523219/b314/config.test
/tmp/go-build817523219/b314/config.test
-test.testlogfile=/tmp/go-build817523219/b314/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true o QT x_amd64/vet -p
g/x/net/idna -lang=go1.25 x_amd64/vet go_.�� 64/src/net
ache/go/1.25.7/x64/src/runtime/c-nolocalimports
ache/go/1.25.7/x64/pkg/tool/linu-importcfg 8036719/b171/
crypto/internal/-d` (dns block)
> - Triggering command: `/tmp/go-build2582390263/b318/config.test
/tmp/go-build2582390263/b318/config.test
-test.testlogfile=/tmp/go-build2582390263/b318/testlog.txt
-test.paniconexit0 -test.timeout=10m0s e755�� moby -address x_amd64/vet
-publish-binary
/usr/bin/contain/home/REDACTED/work/_temp/ghcca-node/node -id
x_amd64/vet de/n��
/run/containerd/io.containerd.runtime.v2.task/moby/d20f582628202OUTPUT
delete /opt/containerd/bin/bash s-through=-lpthrbase64
ache/go/1.25.7/x-d ine bash` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build817523219/b332/launcher.test
/tmp/go-build817523219/b332/launcher.test
-test.testlogfile=/tmp/go-build817523219/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ache/go/1.25.7/x64/src/runtime/c-errorsas J4aB/2fPHF0HdMhn8ydxhJ4aB
64/pkg/tool/linux_amd64/vet -I /tmp/go-build151-n -I
64/pkg/tool/linux_amd64/vet go_.�� 8036719/b171=/tmp/go-build .cfg
64/pkg/tool/linux_amd64/vet -p ache/go/1.25.7/x-d -lang=go1.16
64/pkg/tool/linux_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build2582390263/b336/launcher.test
/tmp/go-build2582390263/b336/launcher.test
-test.testlogfile=/tmp/go-build2582390263/b336/testlog.txt
-test.paniconexit0 -test.timeout=10m0s [
�� --prefix=/net/ipv4/neigh/veth8c3e74e
--prefix=/net/ipv6/conf/veth8c3e74e ache/uv/0.10.9/x86_64/git --64
ache/go/1.25.7/x-d /snap/bin/git bash /usr�� --root
/var/run/docker/runtime-runc/moby 64/pkg/tool/linux_amd64/vet
/run/containerd/bash --log-format 619fd60bb04098d5--version
64/pkg/tool/linux_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build817523219/b332/launcher.test
/tmp/go-build817523219/b332/launcher.test
-test.testlogfile=/tmp/go-build817523219/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ache/go/1.25.7/x64/src/runtime/c-errorsas J4aB/2fPHF0HdMhn8ydxhJ4aB
64/pkg/tool/linux_amd64/vet -I /tmp/go-build151-n -I
64/pkg/tool/linux_amd64/vet go_.�� 8036719/b171=/tmp/go-build .cfg
64/pkg/tool/linux_amd64/vet -p ache/go/1.25.7/x-d -lang=go1.16
64/pkg/tool/linux_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build2582390263/b336/launcher.test
/tmp/go-build2582390263/b336/launcher.test
-test.testlogfile=/tmp/go-build2582390263/b336/testlog.txt
-test.paniconexit0 -test.timeout=10m0s [
�� --prefix=/net/ipv4/neigh/veth8c3e74e
--prefix=/net/ipv6/conf/veth8c3e74e ache/uv/0.10.9/x86_64/git --64
ache/go/1.25.7/x-d /snap/bin/git bash /usr�� --root
/var/run/docker/runtime-runc/moby 64/pkg/tool/linux_amd64/vet
/run/containerd/bash --log-format 619fd60bb04098d5--version
64/pkg/tool/linux_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build817523219/b341/mcp.test
/tmp/go-build817523219/b341/mcp.test
-test.testlogfile=/tmp/go-build817523219/b341/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
p=/opt/hostedtoolcache/go/1.25.7/x64=/_/GOROOT .cfg
64/pkg/tool/linux_amd64/vet --gdwarf-5 --64 -o
64/pkg/tool/linux_amd64/vet 8036�� /server/auth.go /server/handlers.go
64/pkg/tool/linux_amd64/vet /tmp/go-build151/usr/bin/runc.original
-imultiarch x86_64-linux-gnu 64/pkg/tool/linux_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build2582390263/b345/mcp.test
/tmp/go-build2582390263/b345/mcp.test
-test.testlogfile=/tmp/go-build2582390263/b345/testlog.txt
-test.paniconexit0 -test.timeout=10m0s crea��
b1f0f2a3ed4d89922f26e357de08e619fd60bb04098d570e
/run/containerd/io.containerd.runtime.v2.task/moby/f41fcf883e64cbb1a392bb10395bbjson
64/pkg/tool/linux_amd64/vet /run/containerd//usr/bin/runc.original l ||
true &amp;&amp; eva--version /usr/bin/base64 64/pkg/tool/linux_amd64/vet
/usr�� .cfg /var/run/docker/runtime-runc/moby
64/pkg/tool/linux_amd64/vet /run/containerd/bash --log-format json with
other checks...&#34;; \
elif command -v golan` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Mar 13, 2026
Addresses duplicate code analysis identifying ~50 lines of structural
duplication across two patterns in `internal/server/unified.go`.

## Changes

### Pattern 1: Backend Tool Call Execution (~40 lines eliminated)

Extracted `executeBackendToolCall` helper consolidating:
- Connection management via `launcher.GetOrLaunchForSession`
- `tools/call` request dispatch
- Backend error checking
- Result unmarshaling

**Before:**
```go
// guardBackendCaller.CallTool and callBackendTool Phase 3 each had:
conn, err := launcher.GetOrLaunchForSession(us.launcher, serverID, sessionID)
if err != nil { ... }
response, err := conn.SendRequestWithServerID(ctx, "tools/call", ...)
if err != nil { ... }
if response.Error != nil { ... }
var result interface{}
json.Unmarshal(response.Result, &result)
```

**After:**
```go
result, err := executeBackendToolCall(ctx, us.launcher, serverID, sessionID, toolName, args)
```

### Pattern 2: Sys Tool Delegation (~10 lines eliminated)

Extracted `callSysServer` helper consolidating:
- Tool name marshaling
- `sysServer.HandleRequest` delegation

**Before:**
```go
// sysInitHandler and sysListHandler each had:
params, _ := json.Marshal(map[string]interface{}{
    "name": toolName,
    "arguments": map[string]interface{}{},
})
result, err := us.sysServer.HandleRequest("tools/call", json.RawMessage(params))
```

**After:**
```go
result, err := us.callSysServer("sys_init")
```

## Impact

- Eliminates copy-paste error risk when modifying backend call or sys
server logic
- Follows existing helper patterns (`newErrorCallToolResult`,
`parseToolArguments`)
- No functional changes—pure refactoring

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build4242760615/b336/launcher.test
/tmp/go-build4242760615/b336/launcher.test
-test.testlogfile=/tmp/go-build4242760615/b336/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -uns�� ache/go/1.25.7/x64/src/net
/tmp/go-build1249286257/b024/vet.cfg
ache/go/1.25.7/x64/pkg/tool/linux_amd64/vet unset position.go
.12/x64/bin/git ache/go/1.25.7/x64/pkg/tool/linuHEAD -W -I
/tmp/go-build1249286257/b165/
ache/go/1.25.7/x64/pkg/tool/linux_amd64/compile . --gdwarf2 --64
ache/go/1.25.7/x64/pkg/tool/linux_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build2320097585/b332/launcher.test
/tmp/go-build2320097585/b332/launcher.test
-test.testlogfile=/tmp/go-build2320097585/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/bin/git ortcfg
/usr/sbin/bash submodules | heanode 9286257/b132/vet-v ndor/bin/git bash
/usr�� runtime-runc/moby ortcfg csi/net-interface-handler
aw-mcpg/internal/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/asm
aw-mcpg/internal-V=full` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build4242760615/b318/config.test
/tmp/go-build4242760615/b318/config.test
-test.testlogfile=/tmp/go-build4242760615/b318/testlog.txt
-test.paniconexit0 -test.timeout=10m0s --de�� c.test --debug-prefix-map
64/bin/git -I /opt/hostedtoolc-unsafeptr=false ut-1969789729.c
VF78F_aidvBPXKXaKR/S4HB-3OSyH3DKHEAD` (dns block)
> - Triggering command: `/tmp/go-build2320097585/b314/config.test
/tmp/go-build2320097585/b314/config.test
-test.testlogfile=/tmp/go-build2320097585/b314/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 17fb9960acf3cdef
-importcfg ine by/b2276789a3c14/usr/bin/chronyc -w -buildmode=exe ine
--ve�� 85e4fa5c5748c5dd -extld=gcc /opt/hostedtoolcache/go/1.25.7/xjson
aw-mcpg/internalbase64 9286257/b151/vet-d ns
/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linu--listen` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build4242760615/b336/launcher.test
/tmp/go-build4242760615/b336/launcher.test
-test.testlogfile=/tmp/go-build4242760615/b336/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -uns�� ache/go/1.25.7/x64/src/net
/tmp/go-build1249286257/b024/vet.cfg
ache/go/1.25.7/x64/pkg/tool/linux_amd64/vet unset position.go
.12/x64/bin/git ache/go/1.25.7/x64/pkg/tool/linuHEAD -W -I
/tmp/go-build1249286257/b165/
ache/go/1.25.7/x64/pkg/tool/linux_amd64/compile . --gdwarf2 --64
ache/go/1.25.7/x64/pkg/tool/linux_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build2320097585/b332/launcher.test
/tmp/go-build2320097585/b332/launcher.test
-test.testlogfile=/tmp/go-build2320097585/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/bin/git ortcfg
/usr/sbin/bash submodules | heanode 9286257/b132/vet-v ndor/bin/git bash
/usr�� runtime-runc/moby ortcfg csi/net-interface-handler
aw-mcpg/internal/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/asm
aw-mcpg/internal-V=full` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build4242760615/b336/launcher.test
/tmp/go-build4242760615/b336/launcher.test
-test.testlogfile=/tmp/go-build4242760615/b336/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -uns�� ache/go/1.25.7/x64/src/net
/tmp/go-build1249286257/b024/vet.cfg
ache/go/1.25.7/x64/pkg/tool/linux_amd64/vet unset position.go
.12/x64/bin/git ache/go/1.25.7/x64/pkg/tool/linuHEAD -W -I
/tmp/go-build1249286257/b165/
ache/go/1.25.7/x64/pkg/tool/linux_amd64/compile . --gdwarf2 --64
ache/go/1.25.7/x64/pkg/tool/linux_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build2320097585/b332/launcher.test
/tmp/go-build2320097585/b332/launcher.test
-test.testlogfile=/tmp/go-build2320097585/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/bin/git ortcfg
/usr/sbin/bash submodules | heanode 9286257/b132/vet-v ndor/bin/git bash
/usr�� runtime-runc/moby ortcfg csi/net-interface-handler
aw-mcpg/internal/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/asm
aw-mcpg/internal-V=full` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build4242760615/b345/mcp.test
/tmp/go-build4242760615/b345/mcp.test
-test.testlogfile=/tmp/go-build4242760615/b345/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -I ache/go/1.25.7/x64/src/net -I
if (a[i] &amp;&amp; a[i] !~ /^[0-9]&#43;$/) exit(2);
      if (a[i] &lt; b[i]) exit(3);
else if (a[i] &gt; b[i]) exit(0) --gdwarf-5 --64 -o
ache/go/1.25.7/x64/pkg/tool/linuHEAD -o
/tmp/go-build1249286257/b210/_pkg_.a -trimpath
ache/go/1.25.7/x64/pkg/tool/linux_amd64/vet -p
github.com/githu/tmp/go-build3632611954/b228/vet.cfg -lang=go1.25
ache/go/1.25.7/x64/pkg/tool/linux_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build2320097585/b341/mcp.test
/tmp/go-build2320097585/b341/mcp.test
-test.testlogfile=/tmp/go-build2320097585/b341/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/internal/strutil/truncat6662819a7d6931901c1593745131476bbash
y CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt&#34;,
&#34;REQUESTS_CA_BUNDLE=/etc/ssl/c--version
by/bd0209c110101/opt/hostedtoolcache/go/1.25.7/x64/pkg/tool/linux_amd64/link
aw-mcpg/internal-o
ache/go/1.25.7/x/tmp/go-build2320097585/b314/config.test docker insp��
551622d230bb31fc-s by/bd0209c110101-w rtificates.crt&#34;,-buildmode=exe
by/a501e7528e5b9bash e330148d0ce51d5e/usr/bin/runc` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Mar 19, 2026
…edup logic (#2123)

The trim→skip-empty→deduplicate→optional-sort pattern was reimplemented
inline in three separate packages, with behavioral drift already present
(silent skip vs. error on duplicate, whitespace rejection in one but not
others).

## Changes

- **`internal/strutil/deduplicate.go`** — new `DeduplicateStrings(input
[]string, sorted bool) []string` canonical helper
- **`internal/strutil/deduplicate_test.go`** — table-driven tests
covering nil input, trim, dedup, sort, and order preservation
- **`internal/difc/sink_server_ids.go`** — replace 14-line inline loop
with `strutil.DeduplicateStrings(serverIDs, true)`; log when entries are
dropped
- **`internal/cmd/flags_difc.go`** — `parseDIFCSinkServerIDs`: keep the
embedded-whitespace error check (not handled by the helper), delegate
dedup to `strutil.DeduplicateStrings`
- **`internal/config/guard_policy.go`** — unchanged;
`normalizeAndValidateScopeArray` returns an error on duplicates rather
than silently dropping them, so it doesn't share the same contract

## Before / After

```go
// Before — ~15 lines repeated inline in SetSinkServerIDs
unique := make(map[string]struct{}, len(serverIDs))
normalized := make([]string, 0, len(serverIDs))
for _, serverID := range serverIDs {
    trimmed := strings.TrimSpace(serverID)
    if trimmed == "" { continue }
    if _, exists := unique[trimmed]; exists {
        duplicateIDs = append(duplicateIDs, trimmed)
        continue
    }
    unique[trimmed] = struct{}{}
    normalized = append(normalized, trimmed)
}
sort.Strings(normalized)

// After
normalized := strutil.DeduplicateStrings(serverIDs, true)
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build1731765213/b332/launcher.test
/tmp/go-build1731765213/b332/launcher.test
-test.testlogfile=/tmp/go-build1731765213/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s conf�� 1.4.0/auth/auth.go
1.4.0/auth/client.go x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build908205860/b328/launcher.test
/tmp/go-build908205860/b328/launcher.test
-test.testlogfile=/tmp/go-build908205860/b328/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true --version y
06bc07c272bb18e2 ntime.v2.task/mosystemd-run containerd.sock x_amd64/vet
ctl insp�� .go {{.Config.OpenSt--property=CPUQuota=5%
/usr/libexec/doc--property=MemoryHigh=170M 64/src/net
ache/go/1.25.8/xinfo x_amd64/vet 45045761271a86c7-collect-logs` (dns
block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1731765213/b317/config.test
/tmp/go-build1731765213/b317/config.test
-test.testlogfile=/tmp/go-build1731765213/b317/testlog.txt
-test.paniconexit0 -test.timeout=10m0s conf�� .go` (dns block)
> - Triggering command: `/tmp/go-build908205860/b313/config.test
/tmp/go-build908205860/b313/config.test
-test.testlogfile=/tmp/go-build908205860/b313/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 9c9123b84b4d4e8c
-tests ash b8a4de3a75e76448grep fe9 x_amd64/compile fe9/init.pid --ve��
c48959766ef0f63f b8a4de3a75e764483c627dce6b038343b5b6efe353b9d178502
&#34;CURL_CA_BUNDLE=/--systemd-cgroup b8a4de3a75e76448git` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build1731765213/b332/launcher.test
/tmp/go-build1731765213/b332/launcher.test
-test.testlogfile=/tmp/go-build1731765213/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s conf�� 1.4.0/auth/auth.go
1.4.0/auth/client.go x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build908205860/b328/launcher.test
/tmp/go-build908205860/b328/launcher.test
-test.testlogfile=/tmp/go-build908205860/b328/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true --version y
06bc07c272bb18e2 ntime.v2.task/mosystemd-run containerd.sock x_amd64/vet
ctl insp�� .go {{.Config.OpenSt--property=CPUQuota=5%
/usr/libexec/doc--property=MemoryHigh=170M 64/src/net
ache/go/1.25.8/xinfo x_amd64/vet 45045761271a86c7-collect-logs` (dns
block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build1731765213/b332/launcher.test
/tmp/go-build1731765213/b332/launcher.test
-test.testlogfile=/tmp/go-build1731765213/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s conf�� 1.4.0/auth/auth.go
1.4.0/auth/client.go x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build908205860/b328/launcher.test
/tmp/go-build908205860/b328/launcher.test
-test.testlogfile=/tmp/go-build908205860/b328/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true --version y
06bc07c272bb18e2 ntime.v2.task/mosystemd-run containerd.sock x_amd64/vet
ctl insp�� .go {{.Config.OpenSt--property=CPUQuota=5%
/usr/libexec/doc--property=MemoryHigh=170M 64/src/net
ache/go/1.25.8/xinfo x_amd64/vet 45045761271a86c7-collect-logs` (dns
block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1731765213/b341/mcp.test
/tmp/go-build1731765213/b341/mcp.test
-test.testlogfile=/tmp/go-build1731765213/b341/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1731765213/b271/vet.cfg flib/difflib.go main x_amd64/cgo`
(dns block)
> - Triggering command: `/tmp/go-build908205860/b337/mcp.test
/tmp/go-build908205860/b337/mcp.test
-test.testlogfile=/tmp/go-build908205860/b337/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true y x_amd64/vet
by/027a141771b2cb8a4de3a75e764483c627dce6b038343b5b6efe353b9d178502/log.json
azero@v1.11.0/bugrep azero@v1.11.0/ca-qE x_amd64/vet 709/log.json 92b4��
by/027a141771b2cb8a4de3a75e764483c627dce6b038343b5b6efe353b9d178502
--bundle
by/027a141771b2cb8a4de3a75e764483c627dce6b038343b5b6efe353b9d178502/init.pid
6efe353b9d178502bash 77a1358e1f687d17/usr/bin/runc x_amd64/vet
table.d/chrony-onoffline` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT CODING AGENT TIPS -->
---

📍 Connect Copilot coding agent with [Jira](https://gh.io/cca-jira-docs),
[Azure Boards](https://gh.io/cca-azure-boards-docs) or
[Linear](https://gh.io/cca-linear-docs) to delegate work to Copilot in
one click without leaving your project management tool.
lpcox added a commit that referenced this pull request Mar 19, 2026
…cating string comparison (#2152)

Two small cleanup items in the Rust guard: `issue_integrity` carried two
never-read parameters (`_owner`, `_repo`) that forced callers to perform
unnecessary string splits, and `tool_rules.rs` was heap-allocating a
`String` on every `actions_get` call just to do an equality check.

## Changes

- **`labels/helpers.rs`** — drop `_owner: &str` and `_repo: &str` from
`issue_integrity` signature
- **`labels/response_items.rs`** — remove `repo_owner` split (existed
solely to fill the dead arg)
- **`labels/response_paths.rs`** — remove `owner` split + stale `//
Extract owner from repo for owner check` comment
- **`labels/mod.rs`** — update all 10 test call sites to match new
signature
- **`labels/tool_rules.rs`** — replace heap-allocating comparison with
zero-allocation `.as_str()` idiom:

```rust
// Before — allocates on every actions_get call
tool_args.get("method") == Some(&Value::String("download_workflow_run_artifact".to_string()))

// After — allocation-free
tool_args.get("method").and_then(|v| v.as_str()) == Some("download_workflow_run_artifact")
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build1926788072/b332/launcher.test
/tmp/go-build1926788072/b332/launcher.test
-test.testlogfile=/tmp/go-build1926788072/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1926788072/b253/vet.cfg 64/src/runtime/cgo
erive-f8a9da973ea849b8.serde_dernet/http x86_64/as
erive-f8a9da973e/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
378038/b011/syma-unsafeptr=false erive-f8a9da973e-unreachable=false
_main.o eriv�� ache/go/1.25.8/x64/src/runtime/cgo1.25.8
CLzi/BTFciEBdHbS8DwRuCLzi x_amd64/vet
erive-f8a9da973e/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
erive-f8a9da973e-atomic -Wl,-Bstatic x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1926788072/b317/config.test
/tmp/go-build1926788072/b317/config.test
-test.testlogfile=/tmp/go-build1926788072/b317/testlog.txt
-test.paniconexit0 -test.timeout=10m0s 2c9e�� 64/src/runtime/cgo
-gnu/lib/libstd-267b04dbd87607fbgithub.com/tetratelabs/wazero/internal/platform
x_amd64/compile
-gnu/lib/libobje/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
378038/b009/ -gnu/lib/libaddr-unreachable=false x_amd64/compile -gnu�� ;
then \
$GOPATH/bin/golangci-lint run --timeout=5m || echo &#34;��� Warning:
golangci-lint failed
/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
-gnu/lib/libstd_detect-3c01aa300-nolocalimports x_amd64/vet
-gnu/lib/librust/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
ry 64-REDACTED-linux-unreachable=false x_amd64/vet` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build1926788072/b332/launcher.test
/tmp/go-build1926788072/b332/launcher.test
-test.testlogfile=/tmp/go-build1926788072/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1926788072/b253/vet.cfg 64/src/runtime/cgo
erive-f8a9da973ea849b8.serde_dernet/http x86_64/as
erive-f8a9da973e/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
378038/b011/syma-unsafeptr=false erive-f8a9da973e-unreachable=false
_main.o eriv�� ache/go/1.25.8/x64/src/runtime/cgo1.25.8
CLzi/BTFciEBdHbS8DwRuCLzi x_amd64/vet
erive-f8a9da973e/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
erive-f8a9da973e-atomic -Wl,-Bstatic x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build1926788072/b332/launcher.test
/tmp/go-build1926788072/b332/launcher.test
-test.testlogfile=/tmp/go-build1926788072/b332/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1926788072/b253/vet.cfg 64/src/runtime/cgo
erive-f8a9da973ea849b8.serde_dernet/http x86_64/as
erive-f8a9da973e/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
378038/b011/syma-unsafeptr=false erive-f8a9da973e-unreachable=false
_main.o eriv�� ache/go/1.25.8/x64/src/runtime/cgo1.25.8
CLzi/BTFciEBdHbS8DwRuCLzi x_amd64/vet
erive-f8a9da973e/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
erive-f8a9da973e-atomic -Wl,-Bstatic x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1926788072/b341/mcp.test
/tmp/go-build1926788072/b341/mcp.test
-test.testlogfile=/tmp/go-build1926788072/b341/testlog.txt
-test.paniconexit0 -test.timeout=10m0s o_.o�� 64/src/net a/dsa.go
x_amd64/vet -p internal/runtime--version -lang=go1.25 x_amd64/vet -o
ew@v1.1.1/spew/bypass.go ew@v1.1.1/spew/common.go x_amd64/vet -p
378038/b107/_cgo-qE -lang=go1.25 x_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT CODING AGENT TIPS -->
---

📱 Kick off Copilot coding agent tasks wherever you are with [GitHub
Mobile](https://gh.io/cca-mobile-docs), available on iOS and Android.
lpcox added a commit that referenced this pull request Mar 24, 2026
…olve broken references from partial refactor (#2393)

Three duplicate-code issues in the guard package and cmd flags: a
misattributed logger bug, structural duplication in `LabelAgent`
implementations, and broken call sites left by a partial inlining
refactor.

## NoopGuard wrong logger (bug)

`noop.go` declared `logNoop = logger.New("guard:noop")` but all four log
calls used the package-level `log` from `context.go` (`guard:context`),
making `logNoop` dead code and silently misattributing all NoopGuard
logs.

```go
// Before — all used wrong logger
log.Printf("Initializing agent labels with noop guard")

// After — correct logger
logNoop.Printf("Initializing agent labels with noop guard")
```

## Extracted `emptyAgentLabelsResult` helper

`NoopGuard.LabelAgent` and `WriteSinkGuard.LabelAgent` duplicated the
same `AgentLabelsPayload{Secrecy: []string{}, Integrity: []string{}}`
construction, differing only in `DIFCMode`. Extracted to `guard.go`:

```go
func emptyAgentLabelsResult(mode string) *LabelAgentResult {
    return &LabelAgentResult{
        Agent:    AgentLabelsPayload{Secrecy: []string{}, Integrity: []string{}},
        DIFCMode: mode,
    }
}
```

Both guards now call
`emptyAgentLabelsResult(difc.ModeStrict/ModeFilter)`.

## Completed partial refactor (broken build)

A prior commit removed `getDefaultGuardPolicyJSON`,
`getDefaultAllowOnlyScopeOwner/Repo/MinIntegrity` from `flags_difc.go`
but left call sites unupdated and introduced duplicate test functions
across config test files:

- Inlined remaining `os.Getenv(...)` calls in `proxy.go` and `root.go`
- Updated `flags_difc_test.go` to use `os.Getenv` directly
- Removed duplicate `TestLoadFromFile_MultipleServers` (now in
`config_core_test.go`), `TestValidateContainerID` and
`TestGetGatewayPortFromEnv` (now in `docker_helpers_and_env_test.go`)
from their respective files

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build3683465988/b333/launcher.test
/tmp/go-build3683465988/b333/launcher.test
-test.testlogfile=/tmp/go-build3683465988/b333/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build3683465988/b299/vet.cfg g_.a 7198098/b151/ x_amd64/vet
/tmp/go-build128/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
ternal/engine/wa-unsafeptr=false` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3683465988/b318/config.test
/tmp/go-build3683465988/b318/config.test
-test.testlogfile=/tmp/go-build3683465988/b318/testlog.txt
-test.paniconexit0 -test.timeout=10m0s go_.�� 64/src/net -trimpath
x_amd64/vet 7198098/b157/ ions =0 x_amd64/vet swit�� ; then \
$GOPATH/bin/golangci-lint run --timeout=5m || echo &#34;��� Warning:
golangci-lint failed
/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
7198098/b151/ 64/pkg/tool/linux_amd64/vet --gdwarf-5 --64 -o
64/pkg/tool/linu/tmp/go-build3683465988/b204/vet.cfg` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build3683465988/b333/launcher.test
/tmp/go-build3683465988/b333/launcher.test
-test.testlogfile=/tmp/go-build3683465988/b333/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build3683465988/b299/vet.cfg g_.a 7198098/b151/ x_amd64/vet
/tmp/go-build128/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
ternal/engine/wa-unsafeptr=false` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build3683465988/b333/launcher.test
/tmp/go-build3683465988/b333/launcher.test
-test.testlogfile=/tmp/go-build3683465988/b333/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build3683465988/b299/vet.cfg g_.a 7198098/b151/ x_amd64/vet
/tmp/go-build128/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
ternal/engine/wa-unsafeptr=false` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3683465988/b342/mcp.test
/tmp/go-build3683465988/b342/mcp.test
-test.testlogfile=/tmp/go-build3683465988/b342/testlog.txt
-test.paniconexit0 -test.timeout=10m0s 7198�� cfg -I
64/pkg/tool/linu-nilfunc --gdwarf-5 --64 /config 64/pkg/tool/linu-tests
cfg /tmp/go-build1287198098/b185/_pkg_.a -trimpath x_amd64/vet -p
7198098/b288/ -lang=go1.25 x_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT CODING AGENT TIPS -->
---

📍 Connect Copilot coding agent with [Jira](https://gh.io/cca-jira-docs),
[Azure Boards](https://gh.io/cca-azure-boards-docs) or
[Linear](https://gh.io/cca-linear-docs) to delegate work to Copilot in
one click without leaving your project management tool.
lpcox added a commit that referenced this pull request Mar 25, 2026
…connection error diagnostics (#2524)

Connection error diagnostic logging was duplicated across
`mcp/connection.go` and `launcher/log_helpers.go` — each independently
printing command/args, error, stderr, and hint analysis for known error
strings (`executable file not found`, `EOF`, `broken pipe`). Adding a
new diagnostic hint required updating both sites; divergence meant
inconsistent output depending on which code path triggered the failure.

## Changes

- **`internal/mcp/errors.go`** (new): Defines `ConnectionErrorContext`
and `LogConnectionError` — the single source of truth for connection
failure diagnostics. Merges hint logic from both original sites:
containerization hints (`IsDirectCommand` + `RunningInContainer`) and
error-string hints. Fields omit gracefully when zero-valued, so both
callers can populate only what they know.

- **`internal/mcp/connection.go`**: Replaces ~35-line inline error block
with a `LogConnectionError` call passing `{ServerID, Command, Args,
StderrOutput}`.

- **`internal/launcher/log_helpers.go`**: `logLaunchError` delegates
entirely to `mcp.LogConnectionError` with full launcher context
(`SessionID`, `Env`, `RunningInContainer`, `IsDirectCommand`,
`StartupTimeout`).

- **`internal/mcp/errors_test.go`** (new): Tests covering all hint
branches, stderr rendering, arg sanitization, and edge cases.

```go
// Before: each site had its own copy of this logic
if strings.Contains(err.Error(), "executable file not found") || ... {
    log.Printf("⚠️  Command '%s' not found in PATH", command)
    ...
}

// After: one shared function with full context
mcp.LogConnectionError(mcp.ConnectionErrorContext{
    ServerID:           serverID,
    SessionID:          sessionID,
    Command:            serverCfg.Command,
    Args:               serverCfg.Args,
    Env:                serverCfg.Env,
    RunningInContainer: l.runningInContainer,
    IsDirectCommand:    isDirectCommand,
    StartupTimeout:     l.startupTimeout,
}, err)
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build3051059008/b329/launcher.test
/tmp/go-build3051059008/b329/launcher.test
-test.testlogfile=/tmp/go-build3051059008/b329/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go dsa/ecdsa.go
p/bin/bash` (dns block)
> - Triggering command: `/tmp/go-build2944181223/b333/launcher.test
/tmp/go-build2944181223/b333/launcher.test
-test.testlogfile=/tmp/go-build2944181223/b333/testlog.txt
-test.paniconexit0 -test.timeout=10m0s ortc�� d -n 10 stmain.go
ache/go/1.25.8/x64/pkg/tool/linux_amd64/link (compatibility issue with
Go 1.25.0). Continuing with other checks...&#34;; \
elif command -v golan
telabs/wazero/in/tmp/go-build4284220926/b202/vet.cfg --64
ache/go/1.25.8/x64/pkg/tool/linux_amd64/link -I 1059008/b224/cmd.test
/launcher/log_helpers.go ker/docker-init -pthread
-Wl,--no-gc-sectdocker-cli-plugin-metadata -fmessage-length=0
ker/docker-init` (dns block)
> - Triggering command: `/tmp/go-build2960403912/b329/launcher.test
/tmp/go-build2960403912/b329/launcher.test
-test.testlogfile=/tmp/go-build2960403912/b329/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
4181223/b314/_pk/run/containerd/io.containerd.runtime.v2.task/moby/83010862c130074fa53cbdec2f66a/usr/lib/networkd-dispatcher/off.d/chrony-onoffline
by/3d68fe704b33a--log-format by/a44f1c6d2c345json
by/3d68fe704b33a/usr/lib/networkd-dispatcher/off.d/chrony-onoffline
300bcc2a4ea80026start
64/pkg/tool/linu83010862c130074fa53cbdec2f66a97b6b568134d8551ff471fd0b14e7d12390
/opt/hostedtoolcache/go/1.25.8/x/var/run/docker/runtime-runc/moby d945��
irdJ/-TWaY8JNiNqMr3rjirdJ 64/pkg/tool/linux_amd64/asm
/opt/hostedtoolcache/go/1.25.8/xjson
/tmp/go-build305/usr/lib/open-iscsi/net-interface-handler 1059008/b165/
x_amd64/compile 4181223/b314/importcfg` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3051059008/b314/config.test
/tmp/go-build3051059008/b314/config.test
-test.testlogfile=/tmp/go-build3051059008/b314/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go Pe6rubutY
x_amd64/vet
copilot.original/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet`
(dns block)
> - Triggering command: `/tmp/go-build2944181223/b318/config.test
/tmp/go-build2944181223/b318/config.test
-test.testlogfile=/tmp/go-build2944181223/b318/testlog.txt
-test.paniconexit0 -test.timeout=10m0s` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build3051059008/b329/launcher.test
/tmp/go-build3051059008/b329/launcher.test
-test.testlogfile=/tmp/go-build3051059008/b329/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go dsa/ecdsa.go
p/bin/bash` (dns block)
> - Triggering command: `/tmp/go-build2944181223/b333/launcher.test
/tmp/go-build2944181223/b333/launcher.test
-test.testlogfile=/tmp/go-build2944181223/b333/testlog.txt
-test.paniconexit0 -test.timeout=10m0s ortc�� d -n 10 stmain.go
ache/go/1.25.8/x64/pkg/tool/linux_amd64/link (compatibility issue with
Go 1.25.0). Continuing with other checks...&#34;; \
elif command -v golan
telabs/wazero/in/tmp/go-build4284220926/b202/vet.cfg --64
ache/go/1.25.8/x64/pkg/tool/linux_amd64/link -I 1059008/b224/cmd.test
/launcher/log_helpers.go ker/docker-init -pthread
-Wl,--no-gc-sectdocker-cli-plugin-metadata -fmessage-length=0
ker/docker-init` (dns block)
> - Triggering command: `/tmp/go-build2960403912/b329/launcher.test
/tmp/go-build2960403912/b329/launcher.test
-test.testlogfile=/tmp/go-build2960403912/b329/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
4181223/b314/_pk/run/containerd/io.containerd.runtime.v2.task/moby/83010862c130074fa53cbdec2f66a/usr/lib/networkd-dispatcher/off.d/chrony-onoffline
by/3d68fe704b33a--log-format by/a44f1c6d2c345json
by/3d68fe704b33a/usr/lib/networkd-dispatcher/off.d/chrony-onoffline
300bcc2a4ea80026start
64/pkg/tool/linu83010862c130074fa53cbdec2f66a97b6b568134d8551ff471fd0b14e7d12390
/opt/hostedtoolcache/go/1.25.8/x/var/run/docker/runtime-runc/moby d945��
irdJ/-TWaY8JNiNqMr3rjirdJ 64/pkg/tool/linux_amd64/asm
/opt/hostedtoolcache/go/1.25.8/xjson
/tmp/go-build305/usr/lib/open-iscsi/net-interface-handler 1059008/b165/
x_amd64/compile 4181223/b314/importcfg` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build3051059008/b329/launcher.test
/tmp/go-build3051059008/b329/launcher.test
-test.testlogfile=/tmp/go-build3051059008/b329/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go dsa/ecdsa.go
p/bin/bash` (dns block)
> - Triggering command: `/tmp/go-build2944181223/b333/launcher.test
/tmp/go-build2944181223/b333/launcher.test
-test.testlogfile=/tmp/go-build2944181223/b333/testlog.txt
-test.paniconexit0 -test.timeout=10m0s ortc�� d -n 10 stmain.go
ache/go/1.25.8/x64/pkg/tool/linux_amd64/link (compatibility issue with
Go 1.25.0). Continuing with other checks...&#34;; \
elif command -v golan
telabs/wazero/in/tmp/go-build4284220926/b202/vet.cfg --64
ache/go/1.25.8/x64/pkg/tool/linux_amd64/link -I 1059008/b224/cmd.test
/launcher/log_helpers.go ker/docker-init -pthread
-Wl,--no-gc-sectdocker-cli-plugin-metadata -fmessage-length=0
ker/docker-init` (dns block)
> - Triggering command: `/tmp/go-build2960403912/b329/launcher.test
/tmp/go-build2960403912/b329/launcher.test
-test.testlogfile=/tmp/go-build2960403912/b329/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
4181223/b314/_pk/run/containerd/io.containerd.runtime.v2.task/moby/83010862c130074fa53cbdec2f66a/usr/lib/networkd-dispatcher/off.d/chrony-onoffline
by/3d68fe704b33a--log-format by/a44f1c6d2c345json
by/3d68fe704b33a/usr/lib/networkd-dispatcher/off.d/chrony-onoffline
300bcc2a4ea80026start
64/pkg/tool/linu83010862c130074fa53cbdec2f66a97b6b568134d8551ff471fd0b14e7d12390
/opt/hostedtoolcache/go/1.25.8/x/var/run/docker/runtime-runc/moby d945��
irdJ/-TWaY8JNiNqMr3rjirdJ 64/pkg/tool/linux_amd64/asm
/opt/hostedtoolcache/go/1.25.8/xjson
/tmp/go-build305/usr/lib/open-iscsi/net-interface-handler 1059008/b165/
x_amd64/compile 4181223/b314/importcfg` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3051059008/b338/mcp.test
/tmp/go-build3051059008/b338/mcp.test
-test.testlogfile=/tmp/go-build3051059008/b338/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/c-p
zGGbXQmyc ache/go/1.25.8/x-lang=go1.24` (dns block)
> - Triggering command: `/tmp/go-build2944181223/b342/mcp.test
/tmp/go-build2944181223/b342/mcp.test
-test.testlogfile=/tmp/go-build2944181223/b342/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -uns��
pkg/mod/github.com/segmentio/asm@v1.1.3/cpu/arm6&#43;30
/tmp/go-build3051059008/b122/vet.cfg x_amd64/link -b
copilot/duplicat/usr/bin/runc 64/bin/bash x_amd64/link -o
/tmp/go-build3051059008/b297/_pkg_.a -trimpath x_amd64/vet -p
qV/wxj7iTUpwRLRu/usr/bin/runc -lang=go1.17 x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build2960403912/b338/mcp.test
/tmp/go-build2960403912/b338/mcp.test
-test.testlogfile=/tmp/go-build2960403912/b338/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT CODING AGENT TIPS -->
---

📍 Connect Copilot coding agent with [Jira](https://gh.io/cca-jira-docs),
[Azure Boards](https://gh.io/cca-azure-boards-docs) or
[Linear](https://gh.io/cca-linear-docs) to delegate work to Copilot in
one click without leaving your project management tool.
lpcox added a commit that referenced this pull request Mar 26, 2026
… HTTP errors (#2582)

Gateway startup fails when `raw.githubusercontent.com` rate-limits the
JSON config schema fetch (HTTP 429). Any transient error was treated as
fatal with no retry.

## Changes

**`internal/config/validation_schema.go`**
- Added `isTransientHTTPError()` identifying 429, 503, and all 5xx codes
- `fetchAndFixSchema()` now retries up to `maxSchemaFetchRetries` (3)
times with exponential backoff (1s → 2s) for transient errors; permanent
errors (4xx except 429) fail immediately
- `schemaFetchRetryDelay` and `schemaHTTPClientTimeout` are
package-level vars so tests can zero them out without sleeps

**`internal/config/validation_schema_fetch_test.go`**
- `init()` sets zero delay + 200ms HTTP timeout for all tests in the
file
- `TestFetchAndFixSchema_HTTPError` extended with 429 case and
per-error-type request-count assertions (1 request for permanent, 3 for
transient)
- Added `TestFetchAndFixSchema_RetrySucceedsAfterTransientError`: 2×429
→ 200 succeeds
- Added `TestFetchAndFixSchema_ExponentialBackoffDelays`: verifies
exactly `maxSchemaFetchRetries` requests are made on persistent
transient failure

**Note**: The secrecy-vs-integrity notice labeling fix (Problem 2 from
the issue) is already present in the codebase (`difcPolicyLabel()` +
`IsSecrecyViolation` in `difc_log.go` / `difc/resource.go`).

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build3732201295/b330/launcher.test
/tmp/go-build3732201295/b330/launcher.test
-test.testlogfile=/tmp/go-build3732201295/b330/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true g_.a --global git
pull.rebase abis` (dns block)
> - Triggering command: `/tmp/go-build63582137/b334/launcher.test
/tmp/go-build63582137/b334/launcher.test
-test.testlogfile=/tmp/go-build63582137/b334/testlog.txt
-test.paniconexit0 -test.timeout=10m0s` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3732201295/b315/config.test
/tmp/go-build3732201295/b315/config.test
-test.testlogfile=/tmp/go-build3732201295/b315/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true -c=4 -nolocalimports
-importcfg /tmp/go-build3732201295/b287/importcfg -pack
/home/REDACTED/go/pkg/mod/github.com/modelcontextprotocol/go-sdk@v1.4.1/auth/auth.go
/home/REDACTED/go/pkg/mod/github.com/modelcontextprotocol/go-sdk@v1.4.1/auth/client.go
ortc�� go 9p-W5oE9v ache/go/1.25.8/x64/pkg/tool/linu-Werror
credential.helpe/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/compile`
(dns block)
> - Triggering command: `/tmp/go-build2566417517/b001/config.test
/tmp/go-build2566417517/b001/config.test
-test.testlogfile=/tmp/go-build2566417517/b001/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.run=TestFetchAndFixSchema
-test.v=true ache/go/1.25.8/x64/src/crypto/ec-ifaceassert x_amd64/vet -p
internal/reflectdocker-cli-plugin-metadata -lang=go1.25 x_amd64/vet ap
2201295/b171=/tmp/go-build .cfg 64/pkg/tool/linux_amd64/vet -p
ache/go/1.25.8/x-c -lang=go1.25 64/pkg/tool/linux_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build1075949314/b001/config.test
/tmp/go-build1075949314/b001/config.test
-test.testlogfile=/tmp/go-build1075949314/b001/testlog.txt
-test.paniconexit0 -test.run=TestFetchAndFixSchema -test.v=true
-test.timeout=30s SkhS/x3QNW0bkE1zmain 64/pkg/tool/linu-lang=go1.25 -I
/tmp/go-build373docker-cli-plugin-metadata -I
64/pkg/tool/linu-dwarf=false 2201�� azero@v1.11.0/ingo1.25.8
azero@v1.11.0/in-c=4 64/pkg/tool/linu-nolocalimports 2201295/b165/
/dev/null ctor
64/pkg/tool/linu/tmp/go-build3732201295/b345/_testmain.go` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build3732201295/b330/launcher.test
/tmp/go-build3732201295/b330/launcher.test
-test.testlogfile=/tmp/go-build3732201295/b330/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true g_.a --global git
pull.rebase abis` (dns block)
> - Triggering command: `/tmp/go-build63582137/b334/launcher.test
/tmp/go-build63582137/b334/launcher.test
-test.testlogfile=/tmp/go-build63582137/b334/testlog.txt
-test.paniconexit0 -test.timeout=10m0s` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build3732201295/b330/launcher.test
/tmp/go-build3732201295/b330/launcher.test
-test.testlogfile=/tmp/go-build3732201295/b330/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true g_.a --global git
pull.rebase abis` (dns block)
> - Triggering command: `/tmp/go-build63582137/b334/launcher.test
/tmp/go-build63582137/b334/launcher.test
-test.testlogfile=/tmp/go-build63582137/b334/testlog.txt
-test.paniconexit0 -test.timeout=10m0s` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3732201295/b339/mcp.test
/tmp/go-build3732201295/b339/mcp.test
-test.testlogfile=/tmp/go-build3732201295/b339/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
committer.name x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build63582137/b343/mcp.test
/tmp/go-build63582137/b343/mcp.test
-test.testlogfile=/tmp/go-build63582137/b343/testlog.txt
-test.paniconexit0 -test.timeout=10m0s ortc�� TOKEN&#34;; }; f get
TOKEN&#34;; }; f get ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
-pthread telabs/wazero -fmessage-length=0
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet -I eNqb/Hpbq2t4bcSrSRPw9eNqb
-I x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT CODING AGENT TIPS -->
---

📍 Connect Copilot coding agent with [Jira](https://gh.io/cca-jira-docs),
[Azure Boards](https://gh.io/cca-azure-boards-docs) or
[Linear](https://gh.io/cca-linear-docs) to delegate work to Copilot in
one click without leaving your project management tool.
lpcox added a commit that referenced this pull request Mar 26, 2026
…ver session timeout (#2597)

Long-running agent workflows (~30+ min) fail when the gateway's HTTP
session to a backend (e.g. safeoutputs) expires mid-run. The agent
receives `session not found` from the backend and enters a futile retry
loop rather than recovering.

## Changes

### Client-side session reconnect (`internal/mcp/connection.go`,
`http_transport.go`)

- **Plain JSON-RPC transport**: `sendHTTPRequest` detects HTTP 404 +
`"session not found"` body, calls `reconnectPlainJSON()` to
re-initialize the session, then retries the original request once.
- **SDK transports (streamable / SSE)**: `callSDKMethodWithReconnect()`
wraps all SDK method calls — on a `"session not found"` error it calls
`reconnectSDKTransport()` (closes the dead session, dials a new one) and
retries once. `SendRequestWithServerID` now routes through this wrapper
for SDK transports.
- **Thread safety**: `sessionMu sync.RWMutex` protects `httpSessionID`,
`session`, and `client`. All reads go through `getSDKSession()` /
`getHTTPSessionID()` (under `RLock`); reconnect functions hold the full
`Lock`.

```go
// Plain JSON-RPC: sendHTTPRequest now does this automatically
result, err := c.executeHTTPRequest(...)
if isSessionNotFoundHTTPResponse(result.StatusCode, result.ResponseBody) {
    if reconnErr := c.reconnectPlainJSON(); reconnErr == nil {
        result, err = c.executeHTTPRequest(...)  // retry once
    }
}

// SDK transports (streamable / SSE): via callSDKMethodWithReconnect
result, err := c.callSDKMethod(method, params)
if err != nil && isSessionNotFoundError(err) {
    if reconnErr := c.reconnectSDKTransport(); reconnErr == nil {
        result, err = c.callSDKMethod(method, params)
    }
}
```

### Server-side idle timeout (`internal/server/transport.go`)

`SessionTimeout` increased from `30m → 2h` so the agent→gateway inbound
session doesn't expire during extended periods of no MCP activity (e.g.
a long `lake build`).

### Tests (`internal/mcp/http_transport_test.go`)

Added `TestSendHTTPRequest_ReconnectsOnSessionNotFound`,
`TestSendHTTPRequest_ReconnectFailure`,
`TestSendHTTPRequest_NoReconnectOnOtherErrors`, plus unit tests for
`isSessionNotFoundError` and `isSessionNotFoundHTTPResponse`.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build2012957444/b330/launcher.test
/tmp/go-build2012957444/b330/launcher.test
-test.testlogfile=/tmp/go-build2012957444/b330/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true g_.a --local es
committer.email go` (dns block)
> - Triggering command: `/tmp/go-build916828748/b330/launcher.test
/tmp/go-build916828748/b330/launcher.test
-test.testlogfile=/tmp/go-build916828748/b330/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
aw-mcpg/internal/config/rules/rules.go
aw-mcpg/internal/config/rules/rules_test.go
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet . contextprotocol/checkout
--64 ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet -I
Scom/odrQfnn_R7r_as4UScom -I
/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linu-lang=go1.25 --gdwarf-5
--64 -o 2957444/b291/importcfg` (dns block)
> - Triggering command: `/tmp/go-build1482963661/b334/launcher.test
/tmp/go-build1482963661/b334/launcher.test
-test.testlogfile=/tmp/go-build1482963661/b334/testlog.txt
-test.paniconexit0 -test.timeout=10m0s --ve��
/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/internal/guard/context.go
/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/internal/guard/guard.go ash
b128.go s2rJ-u63W ache/go/1.25.8/x/tmp/go-build3142434740/b172/vet.cfg
nIQTNFClwl8R --ve��` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2012957444/b315/config.test
/tmp/go-build2012957444/b315/config.test
-test.testlogfile=/tmp/go-build2012957444/b315/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true -c=4 -nolocalimports
-importcfg /tmp/go-build2012957444/b289/importcfg -pack
/home/REDACTED/go/pkg/mod/golang.org/x/oauth2@v0.34.0/deviceauth.go
/home/REDACTED/go/pkg/mod/golang.org/x/oauth2@v0.34.0/oauth2.go ortc��
rLdqHevS3 64/src/internal/byteorder/byteor--gdwarf2 x_amd64/vet
pull.rebase abis` (dns block)
> - Triggering command: `/tmp/go-build588503108/b315/config.test
/tmp/go-build588503108/b315/config.test
-test.testlogfile=/tmp/go-build588503108/b315/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ache/go/1.25.8/x64/src/runtime/c-I` (dns block)
> - Triggering command: `/tmp/go-build1482963661/b319/config.test
/tmp/go-build1482963661/b319/config.test
-test.testlogfile=/tmp/go-build1482963661/b319/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -o d -n 10 -importcfg
2957444/b370=&gt; -s -w -buildmode=exe /usr/bin/runc.original --ve�� it
tests...&#34; -extld=gcc x_amd64/vet
64/src/runtime/c/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
credential.helpe/tmp/go-build3142434740/b239/vet.cfg
ache/go/1.25.8/x-lang=go1.17 x_amd64/vet` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build2012957444/b330/launcher.test
/tmp/go-build2012957444/b330/launcher.test
-test.testlogfile=/tmp/go-build2012957444/b330/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true g_.a --local es
committer.email go` (dns block)
> - Triggering command: `/tmp/go-build916828748/b330/launcher.test
/tmp/go-build916828748/b330/launcher.test
-test.testlogfile=/tmp/go-build916828748/b330/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
aw-mcpg/internal/config/rules/rules.go
aw-mcpg/internal/config/rules/rules_test.go
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet . contextprotocol/checkout
--64 ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet -I
Scom/odrQfnn_R7r_as4UScom -I
/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linu-lang=go1.25 --gdwarf-5
--64 -o 2957444/b291/importcfg` (dns block)
> - Triggering command: `/tmp/go-build1482963661/b334/launcher.test
/tmp/go-build1482963661/b334/launcher.test
-test.testlogfile=/tmp/go-build1482963661/b334/testlog.txt
-test.paniconexit0 -test.timeout=10m0s --ve��
/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/internal/guard/context.go
/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/internal/guard/guard.go ash
b128.go s2rJ-u63W ache/go/1.25.8/x/tmp/go-build3142434740/b172/vet.cfg
nIQTNFClwl8R --ve��` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build2012957444/b330/launcher.test
/tmp/go-build2012957444/b330/launcher.test
-test.testlogfile=/tmp/go-build2012957444/b330/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true g_.a --local es
committer.email go` (dns block)
> - Triggering command: `/tmp/go-build916828748/b330/launcher.test
/tmp/go-build916828748/b330/launcher.test
-test.testlogfile=/tmp/go-build916828748/b330/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
aw-mcpg/internal/config/rules/rules.go
aw-mcpg/internal/config/rules/rules_test.go
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet . contextprotocol/checkout
--64 ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet -I
Scom/odrQfnn_R7r_as4UScom -I
/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linu-lang=go1.25 --gdwarf-5
--64 -o 2957444/b291/importcfg` (dns block)
> - Triggering command: `/tmp/go-build1482963661/b334/launcher.test
/tmp/go-build1482963661/b334/launcher.test
-test.testlogfile=/tmp/go-build1482963661/b334/testlog.txt
-test.paniconexit0 -test.timeout=10m0s --ve��
/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/internal/guard/context.go
/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/internal/guard/guard.go ash
b128.go s2rJ-u63W ache/go/1.25.8/x/tmp/go-build3142434740/b172/vet.cfg
nIQTNFClwl8R --ve��` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2012957444/b339/mcp.test
/tmp/go-build2012957444/b339/mcp.test
-test.testlogfile=/tmp/go-build2012957444/b339/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo o
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build916828748/b339/mcp.test
/tmp/go-build916828748/b339/mcp.test
-test.testlogfile=/tmp/go-build916828748/b339/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 2957444/b308/_pkg_.a
/tmp/go-build2012957444/b165/
ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile . contextprotocol/-c
--64 ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile -I
2957444/b320/_pkg_.a -I docker-buildx --gdwarf-5 b/gh-aw-mcpg/int--norc
-o docker-buildx` (dns block)
> - Triggering command: `/tmp/go-build1482963661/b343/mcp.test
/tmp/go-build1482963661/b343/mcp.test
-test.testlogfile=/tmp/go-build1482963661/b343/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -o ssue -importcfg x_amd64/vet -s
-w -buildmode=exe x_amd64/vet --no�� --noprofile -extld=gcc x_amd64/vet
ternal/engine/wabash ternal/engine/wa/usr/bin/runc x_amd64/compile
x_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT CODING AGENT TIPS -->
---

⚡ Quickly spin up Copilot coding agent tasks from anywhere on your macOS
or Windows machine with [Raycast](https://gh.io/cca-raycast-docs).
lpcox added a commit that referenced this pull request Mar 29, 2026
…andling (#2790)

Three structural duplication patterns in `internal/logger`,
`internal/config`, and `internal/server` accumulated ~500 lines of
repetitive boilerplate with divergence risk.

## Logger initialization closures → named functions
Each `Init*Logger` function used anonymous inline closures for setup and
error handling. Extracted to named package-level functions per logger
type:

```go
// Before: anonymous closures inline in InitFileLogger
logger, err := initLogger(logDir, fileName, os.O_APPEND,
    func(file *os.File, logDir, fileName string) (*FileLogger, error) { ... },
    func(err error, logDir, fileName string) (*FileLogger, error) { ... },
)

// After: named functions
logger, err := initLogger(logDir, fileName, os.O_APPEND, setupFileLogger, handleFileLoggerError)
```

Applied to `FileLogger`, `MarkdownLogger`, `JSONLLogger`, and
`ToolsLogger`.

## Validation log helpers
30+ near-identical `logValidation.Printf(...)` calls in `validation.go`
standardized via three helpers:

```go
func logValidateServerStart(name, serverType string)
func logValidateServerPassed(name string)
func logValidateServerFailed(name, reason string)
```

## `withLock` helper on logger types
Replaced repeated `mu.Lock() / defer mu.Unlock()` preambles with a
per-type `withLock(fn func() error) error` method on `FileLogger`,
`JSONLLogger`, `MarkdownLogger`, and `ToolsLogger`. Updated `Close()`
and write methods accordingly.

## `session.go` double-checked locking → `syncutil.GetOrCreate`
`requireSession` previously hand-rolled read→check→write→double-check
locking. Replaced with the existing `syncutil.GetOrCreate` helper (same
pattern already used in `server_file_logger.go`):

```go
isNew := false
if _, err := syncutil.GetOrCreate(&us.sessionMu, us.sessions, sessionID, func() (*Session, error) {
    s := NewSession(sessionID, "")
    isNew = true
    return s, nil
}); err != nil {
    return err
}
```

Updated `common.go` documentation to reflect the new `withLock` and
named-function patterns.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build758752077/b330/launcher.test
/tmp/go-build758752077/b330/launcher.test
-test.testlogfile=/tmp/go-build758752077/b330/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go --local 86_64/as
user.email` (dns block)
> - Triggering command: `/tmp/go-build972084089/b334/launcher.test
/tmp/go-build972084089/b334/launcher.test
-test.testlogfile=/tmp/go-build972084089/b334/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2374296311/b001/vet.cfg ache/go/1.25.8/x64/src/net
64/src/encoding/gob/dec_helpers.go cfg -I . -imultiarch
ache/go/1.25.8/x-buildtags -uns�� 752077/b258/_pkg-errorsas
/tmp/go-build758-ifaceassert ache/go/1.25.8/x-nilfunc _amd64.s
telabs/wazero/in-atomic -D_FORTIFY_SOURC-bool
ache/go/1.25.8/x-buildtags` (dns block)
> - Triggering command: `/tmp/go-build2612040108/b334/launcher.test
/tmp/go-build2612040108/b334/launcher.test
-test.testlogfile=/tmp/go-build2612040108/b334/testlog.txt
-test.paniconexit0 -test.timeout=10m0s /usr�� ry=1
ga/m4mMaA4EfUuX_-tests bash
/opt/hostedtoolc/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
cfg 64/pkg/tool/linu/tmp/go-build532890590/b158/vet.cfg bash --no��
--noprofile 64/pkg/tool/linux_amd64/vet .13/x64/bash se cfg x_amd64/vet
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet` (dns block)
> - `https://api.github.com/graphql`
> - Triggering command: `/usr/bin/gh gh issue close 2755 --repo
github/gh-aw-mcpg --comment Resolved in PR #2790: refactored logger
initialization closures to named functions, added validation log
helpers, added withLock helpers to logger types, and refactored
requireSession to use syncutil.GetOrCreate.
by/734792accd854/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/compile
065 -lang=go1.25 065/init.pid 644 9221a53b1917004b-p
runtime-runc/mobgithub.com/github/gh-aw-mcpg/internal/server
/systemd-sysctl io.containerd.rugit -c=4
-certificates.crcopilot/duplicate-code-analysis-report 31d/log.json`
(http block)
> - Triggering command: `/usr/bin/gh gh issue close 2756 --repo
github/gh-aw-mcpg --comment Resolved in PR #2790: refactored logger
initialization closures to named functions, added validation log
helpers, added withLock helpers to logger types, and refactored
requireSession to use syncutil.GetOrCreate. -errorsas 065 -nilfunc`
(http block)
> - Triggering command: `/usr/bin/gh gh issue close 2757 --repo
github/gh-aw-mcpg --comment Resolved in PR #2790: refactored logger
initialization closures to named functions, added validation log
helpers, added withLock helpers to logger types, and refactored
requireSession to use syncutil.GetOrCreate.
io.containerd.ru/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/link
a8d469f49c8ee67b-o
084089/b330/vet./tmp/go-build1108576084/b001/server.test
/usr/bin/runc.or-importcfg init�� 64/pkg/tool/linu-s y ctl
ntime.v2.task/mogit -buildtags
64/pkg/tool/linucopilot/duplicate-code-analysis-report ctl` (http block)
> - `https://api.github.com/repos/github/gh-aw-mcpg/issues/2754`
> - Triggering command: `/usr/bin/gh gh api -X PATCH
repos//issues/2754 -f state=closed
&#34;CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt&#34;,
&#34;REQUESTS_CA_Bcopilot/duplicate-code-analysis-report
ntime.v2.task/modocker main -lang=go1.25 table.d/chrony-onoffline /usr��
d -n 10 /var/run/docker/runtime-runc/moby iginal /run/containerd/git
--log-format 908/log.json iginal` (http block)
> - `https://api.github.com/repos/github/gh-aw-mcpg/issues/2755`
> - Triggering command: `/usr/bin/gh gh api -X PATCH
repos//issues/2755 -f state=closed /bin/java
io.containerd.ru/usr/libexec/docker/cli-plugins/docker-buildx
-ifaceassert -nilfunc /bin/java /usr�� d -n 10
io.containerd.runtime.v2.task/moby/ec75429440bf8--log-format
erd-shim-runc-v2 io.containerd.rugit 849bc50063d4bbbaadd json
erd-shim-runc-v2-v` (http block)
> - Triggering command: `/usr/bin/curl curl -s -X PATCH REDACTED -H
Authorization: token ****** -H Content-Type: application/json -d
{&#34;state&#34;:&#34;closed&#34;}
aw-mcpg/test/integration/start_gateway_with_pipe.sh --ro��
115b774795f51db055fc7f996e03d7a54f3702b53ed9bbf2 runtime-runc/moby
re-commit-msg io.containerd.rubash functions for l--norc
--systemd-cgroup--noprofile re-commit-msg` (http block)
> - Triggering command: `/usr/bin/curl curl -v -X PATCH REDACTED -H
Authorization: token ****** -H Content-Type: application/json -d
{&#34;state&#34;:&#34;closed&#34;} csi/net-interfac-v 954f��
l/config/validation.go
io.containerd.runtime.v2.task/moby/901063bdb288e--log-format bin/bash
io.containerd.rubash a361f2191e0cbe7c--norc json docker` (http block)
> - `https://api.github.com/repos/github/gh-aw-mcpg/issues/2756`
> - Triggering command: `/usr/bin/gh gh api -X PATCH
repos//issues/2756 -f state=closed /bin/java
da27db1da389d8d6/usr/libexec/docker/cli-plugins/docker-buildx
-ifaceassert df1eeab6e3b61bce271/log.json /bin/java /usr��
/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib y bash
ntime.v2.task/mogit --log-format df1eeab6e3b61bce. bash` (http block)
> - `https://api.github.com/repos/github/gh-aw-mcpg/issues/2757`
> - Triggering command: `/usr/bin/gh gh api -X PATCH
repos//issues/2757 -f state=closed
d-dispatcher/off.d/chrony-onoffline ntime.v2.task/modocker -buildtags
d0d99cb50954aa1dd34960fd0baf0e9b. d-dispatcher/off.d/chrony-onoffline
--ro�� d -n 10 y deql ntime.v2.task/mogit df1eeab6e3b61bceadd
c9934293d0945041. deql` (http block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build758752077/b315/config.test
/tmp/go-build758752077/b315/config.test
-test.testlogfile=/tmp/go-build758752077/b315/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go1.25.8 -c=4
-nolocalimports -importcfg /tmp/go-build758752077/b192/importcfg -pack
/opt/hostedtoolcache/go/1.25.8/x64/src/net/http/httptest/httptest.go
rtcf�� eee754.go W2BDEJWaf
ache/go/1.25.8/x-ffile-prefix-map=/opt/hostedtoolcache/go/1.25.8/x64=/_/GOROOT
pull.rebase` (dns block)
> - Triggering command: `/tmp/go-build837462839/b315/config.test
/tmp/go-build837462839/b315/config.test
-test.testlogfile=/tmp/go-build837462839/b315/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ache/go/1.25.8/x64/src/runtime/c-p Jxl7/weSoYHfkM6pMRgR2Jxl7
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build972084089/b319/config.test
/tmp/go-build972084089/b319/config.test
-test.testlogfile=/tmp/go-build972084089/b319/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1849658217/b202/vet.cfg 9lJ78QKSc
/tmp/go-build758752077/b019/vet.cfg
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build758752077/b330/launcher.test
/tmp/go-build758752077/b330/launcher.test
-test.testlogfile=/tmp/go-build758752077/b330/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go --local 86_64/as
user.email` (dns block)
> - Triggering command: `/tmp/go-build972084089/b334/launcher.test
/tmp/go-build972084089/b334/launcher.test
-test.testlogfile=/tmp/go-build972084089/b334/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2374296311/b001/vet.cfg ache/go/1.25.8/x64/src/net
64/src/encoding/gob/dec_helpers.go cfg -I . -imultiarch
ache/go/1.25.8/x-buildtags -uns�� 752077/b258/_pkg-errorsas
/tmp/go-build758-ifaceassert ache/go/1.25.8/x-nilfunc _amd64.s
telabs/wazero/in-atomic -D_FORTIFY_SOURC-bool
ache/go/1.25.8/x-buildtags` (dns block)
> - Triggering command: `/tmp/go-build2612040108/b334/launcher.test
/tmp/go-build2612040108/b334/launcher.test
-test.testlogfile=/tmp/go-build2612040108/b334/testlog.txt
-test.paniconexit0 -test.timeout=10m0s /usr�� ry=1
ga/m4mMaA4EfUuX_-tests bash
/opt/hostedtoolc/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
cfg 64/pkg/tool/linu/tmp/go-build532890590/b158/vet.cfg bash --no��
--noprofile 64/pkg/tool/linux_amd64/vet .13/x64/bash se cfg x_amd64/vet
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build758752077/b330/launcher.test
/tmp/go-build758752077/b330/launcher.test
-test.testlogfile=/tmp/go-build758752077/b330/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go --local 86_64/as
user.email` (dns block)
> - Triggering command: `/tmp/go-build972084089/b334/launcher.test
/tmp/go-build972084089/b334/launcher.test
-test.testlogfile=/tmp/go-build972084089/b334/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2374296311/b001/vet.cfg ache/go/1.25.8/x64/src/net
64/src/encoding/gob/dec_helpers.go cfg -I . -imultiarch
ache/go/1.25.8/x-buildtags -uns�� 752077/b258/_pkg-errorsas
/tmp/go-build758-ifaceassert ache/go/1.25.8/x-nilfunc _amd64.s
telabs/wazero/in-atomic -D_FORTIFY_SOURC-bool
ache/go/1.25.8/x-buildtags` (dns block)
> - Triggering command: `/tmp/go-build2612040108/b334/launcher.test
/tmp/go-build2612040108/b334/launcher.test
-test.testlogfile=/tmp/go-build2612040108/b334/testlog.txt
-test.paniconexit0 -test.timeout=10m0s /usr�� ry=1
ga/m4mMaA4EfUuX_-tests bash
/opt/hostedtoolc/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
cfg 64/pkg/tool/linu/tmp/go-build532890590/b158/vet.cfg bash --no��
--noprofile 64/pkg/tool/linux_amd64/vet .13/x64/bash se cfg x_amd64/vet
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build758752077/b339/mcp.test
/tmp/go-build758752077/b339/mcp.test
-test.testlogfile=/tmp/go-build758752077/b339/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true go --local
ndor/bin/as committer.name` (dns block)
> - Triggering command: `/tmp/go-build972084089/b343/mcp.test
/tmp/go-build972084089/b343/mcp.test
-test.testlogfile=/tmp/go-build972084089/b343/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -uns�� -unreachable=false
/tmp/go-build758752077/b059/vet.cfg
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet -dumpbase _cgo_.c
-dumpbase-ext ache/go/1.25.8/x-importcfg -I /opt/hostedtoolc-s -I bash
--gdwarf-5 --64 -o /opt/hostedtoolc-extld=gcc` (dns block)
> - Triggering command: `/tmp/go-build2612040108/b343/mcp.test
/tmp/go-build2612040108/b343/mcp.test
-test.testlogfile=/tmp/go-build2612040108/b343/testlog.txt
-test.paniconexit0 -test.timeout=10m0s --no�� --noprofile
pA/uZZaPODy050ia-buildtags docker-buildx
/opt/hostedtoolc/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
cfg 64/pkg/tool/linu/tmp/go-build532890590/b139/vet.cfg docker-buildx
-ato�� /logger/common.go /logger/file_logger.go
64/pkg/tool/linux_amd64/compile -errorsas -ifaceassert -nilfunc
64/pkg/tool/linux_amd64/compile` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 Send tasks to Copilot coding agent from
[Slack](https://gh.io/cca-slack-docs) and
[Teams](https://gh.io/cca-teams-docs) to turn conversations into code.
Copilot posts an update in your thread when it's finished.
lpcox added a commit that referenced this pull request Mar 31, 2026
The gateway schema was fetched at runtime from a pinned GitHub raw URL,
causing startup failures in network-restricted environments and
introducing a hard dependency on external availability.

## Changes

- **Embed schema at build time**: Added
`internal/config/schema/mcp-gateway-config.schema.json` (v0.64.4) and a
`//go:embed` directive with a `embeddedSchemaBytes` variable.
`getOrCompileSchema()` now uses the embedded bytes directly — no network
request.

- **Extract transformation logic**: Split `fetchAndFixSchema` into two
functions:
- `fixSchemaBytes([]byte) ([]byte, error)` — pure JSON transformation
(negative-lookahead fix, registry/guard-policies injection)
- `fetchAndFixSchema(url string) ([]byte, error)` — HTTP fetch +
`fixSchemaBytes`, retained for custom server schema validation

- **Remove `schemaURL` package var**: The hardcoded GitHub URL is no
longer needed for the main schema path. Update instructions are in the
comment on `embeddedSchemaBytes`.

- **Simplify tests**: `fetch_and_fix_schema_test.go` tests now call
`fixSchemaBytes` directly with marshaled JSON instead of spinning up
HTTP mock servers.

```go
// Before: fetched from GitHub at runtime
schemaJSON, fetchErr := fetchAndFixSchema(schemaURL)

// After: uses bundled schema, zero network dependency
schemaJSON, fixErr := fixSchemaBytes(embeddedSchemaBytes)
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build1174324405/b340/launcher.test
/tmp/go-build1174324405/b340/launcher.test
-test.testlogfile=/tmp/go-build1174324405/b340/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1174324405/b240/vet.cfg se 8413017/b047/vet.cfg
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet --gdwarf-5 --64 -o
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build31076197/b001/config.test
/tmp/go-build31076197/b001/config.test
-test.testlogfile=/tmp/go-build31076197/b001/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.run=TestFetchAndFixSchema
-test.v=true --local .13/x64/as user.email` (dns block)
> - Triggering command: `/tmp/go-build2540153460/b001/config.test
/tmp/go-build2540153460/b001/config.test
-test.testlogfile=/tmp/go-build2540153460/b001/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo
64/src/log/internal/internal.go ache/go/1.25.8/x64/pkg/tool/linu-o
gpg.program` (dns block)
> - Triggering command: `/tmp/go-build3088080346/b001/config.test
/tmp/go-build3088080346/b001/config.test
-test.testlogfile=/tmp/go-build3088080346/b001/testlog.txt
-test.paniconexit0 -test.timeout=10m0s go_.�� 8958092/b096/_pkg_.a` (dns
block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build1174324405/b340/launcher.test
/tmp/go-build1174324405/b340/launcher.test
-test.testlogfile=/tmp/go-build1174324405/b340/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1174324405/b240/vet.cfg se 8413017/b047/vet.cfg
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet --gdwarf-5 --64 -o
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build1174324405/b340/launcher.test
/tmp/go-build1174324405/b340/launcher.test
-test.testlogfile=/tmp/go-build1174324405/b340/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1174324405/b240/vet.cfg se 8413017/b047/vet.cfg
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet --gdwarf-5 --64 -o
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1174324405/b349/mcp.test
/tmp/go-build1174324405/b349/mcp.test
-test.testlogfile=/tmp/go-build1174324405/b349/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1174324405/b256/vet.cfg se 8413017/b038/vet.cfg
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet (compatibility issue with Go
1.25.0). Continuing with other checks...&#34;; \
elif command -v golan vendor/golang.or-unsafeptr=false -lang=go1.25
ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 9, 2026
… on missing policy (#3413)

The DIFC proxy's GraphQL rewriter blindly injected `authorAssociation`
into **all** `nodes {}` blocks via `ReplaceAllString`. Queries with
`assignees`, `participants`, `labels`, etc. failed with `Field
'authorAssociation' doesn't exist on type 'User'`. Separately, 503
responses from missing `--policy` were not logged, making debugging
costly.

### GraphQL injection fix

- Added safe-parent allowlists per field group — only inject into `nodes
{}` blocks whose parent connection returns types that actually have the
field:
- Issue/PR fields (`author{login}`, `authorAssociation`):
`pullRequests`, `issues`, `comments`, `reviews`, `search`
  - Commit fields (`author{user{login}}`): `history`
- Added `findParentField()` — walks backward from each `nodes {` match
to extract the enclosing connection field name, handling args and nested
braces
- `fieldsForTool()` now returns `([]guardFieldSet, map[string]bool)` to
thread safe parents through to injection

Before (breaks on `assignees.nodes → User`):
```graphql
assignees(first:100) { nodes {authorAssociation, login } }
```

After (skips unsafe parents):
```graphql
assignees(first:100) { nodes { login } }
comments(first:10) { nodes {author{login},authorAssociation, body } }
```

### 503 logging fix

- Replaced `log.Printf` with `logHandler.Printf` + `logger.LogError` so
missing-policy 503s appear in both debug output and `proxy.log`
- Removed unused `log` import

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build2109691296/b514/launcher.test
/tmp/go-build2109691296/b514/launcher.test
-test.testlogfile=/tmp/go-build2109691296/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -I
olang.org/grpc@v1.80.0/internal/go1.25.8 .cfg x_amd64/vet --gdwarf-5
--64 -o x_amd64/vet -I 2335907/b437/_pkg_.a dU_c/JEVDElkKgVJXLgEedU_c
x_amd64/vet --gdwarf-5 g/grpc/encoding/-atomic -o x_amd64/vet` (dns
block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2109691296/b496/config.test
/tmp/go-build2109691296/b496/config.test
-test.testlogfile=/tmp/go-build2109691296/b496/testlog.txt
-test.paniconexit0 -test.timeout=10m0s ortc�� H/bin/golangci-lint run
--timeout=5m || echo &#34;��� Warning: golangci-lint failed
(compatibility issue with Go 1.25.0). Continuing with other
checks...&#34;; \
elif command -v golan 1.80.0/balancer_wrapper.go
64/pkg/tool/linux_amd64/vet . -imultiarch
x86_64-linux-gnu/tmp/go-build547184664/b347/vet.cfg
64/pkg/tool/linux_amd64/vet 2335�� olang.org/grpc@v1.80.0/internal/-I
olang.org/grpc@v1.80.0/internal//tmp/go-build3905974454/b444/
x_amd64/vet . --gdwarf2 --64 x_amd64/vet` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build2109691296/b514/launcher.test
/tmp/go-build2109691296/b514/launcher.test
-test.testlogfile=/tmp/go-build2109691296/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -I
olang.org/grpc@v1.80.0/internal/go1.25.8 .cfg x_amd64/vet --gdwarf-5
--64 -o x_amd64/vet -I 2335907/b437/_pkg_.a dU_c/JEVDElkKgVJXLgEedU_c
x_amd64/vet --gdwarf-5 g/grpc/encoding/-atomic -o x_amd64/vet` (dns
block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build2109691296/b514/launcher.test
/tmp/go-build2109691296/b514/launcher.test
-test.testlogfile=/tmp/go-build2109691296/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -I
olang.org/grpc@v1.80.0/internal/go1.25.8 .cfg x_amd64/vet --gdwarf-5
--64 -o x_amd64/vet -I 2335907/b437/_pkg_.a dU_c/JEVDElkKgVJXLgEedU_c
x_amd64/vet --gdwarf-5 g/grpc/encoding/-atomic -o x_amd64/vet` (dns
block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2109691296/b523/mcp.test
/tmp/go-build2109691296/b523/mcp.test
-test.testlogfile=/tmp/go-build2109691296/b523/testlog.txt
-test.paniconexit0 -test.timeout=10m0s` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 10, 2026
~10 consecutive `log.Printf` + `logger.LogInfoMd`/`LogWarn` pairs in
`internal/cmd/root.go` log identical startup messages to both stderr and
structured loggers. Every message change must be applied in two places.

### Changes

- **`internal/logger/startup.go`** — Add `StartupInfo` and `StartupWarn`
that combine both calls:

```go
logger.StartupInfo("Starting MCPG in ROUTED mode on %s", listenAddr)
// replaces:
//   log.Printf("Starting MCPG in ROUTED mode on %s", listenAddr)
//   logger.LogInfoMd("startup", "Starting in ROUTED mode on %s", listenAddr)
```

- **`internal/cmd/root.go`** — Replace 11 duplicate pairs with
single-line helper calls
- **`internal/logger/startup_test.go`** — Tests verifying both helpers
write to file and markdown loggers

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build175238182/b510/launcher.test
/tmp/go-build175238182/b510/launcher.test
-test.testlogfile=/tmp/go-build175238182/b510/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ache/go/1.25.8/x-errorsas cgo_.o 64/bin/as -p vendor/golang.or-atomic
-lang=go1.25 238182/b171/_x00-buildtags -p ity/connectivity-errorsas
-trimpath x_amd64/compile -I /tmp/go-build175docker-cli-plugin-metadata
-I x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build3857722332/b514/launcher.test
/tmp/go-build3857722332/b514/launcher.test
-test.testlogfile=/tmp/go-build3857722332/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s rtcf��
pkg/mod/google.golang.org/grpc@v1.80.0/binarylog-s tmain.go x_amd64/vet
/x64=/_/GOROOT --local u/13/cc1 x_amd64/vet -o /tmp/go-build175-errorsas
ettings.Ports}} x_amd64/vet -p go.opentelemetry--version -lang=go1.25
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build516878933/b510/launcher.test
/tmp/go-build516878933/b510/launcher.test
-test.testlogfile=/tmp/go-build516878933/b510/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
7722332/b559/tty.test -tests 7722332/b559/importcfg.link
8NDC/SRjZ7_MrzxIbash pkg/mod/go.opent/usr/bin/runc
ache/go/1.25.8/x--root 97a/log.json U02
io.containerd.ru/run/containerd/io.containerd.runtime.v2.task/moby/83fdf3a250dfab704055af7b451aa/usr/bin/runc.original
{{json .NetworkS--log-format che/go-build/ba/json
by/197def118f828/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
-importcfg x_amd64/vet runc` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build175238182/b492/config.test
/tmp/go-build175238182/b492/config.test
-test.testlogfile=/tmp/go-build175238182/b492/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true ternal/fsapi/fil-p
ternal/fsapi/polgoogle.golang.org/grpc/internal/stats x_amd64/asm
cgo=false false -g&#34; &#34;-lpthread&#34; x_amd64/asm 2381��
238182/b172/_pkg-p
ache/go/1.25.8/xgoogle.golang.org/grpc/health/grpc_health_v1` (dns
block)
> - Triggering command: `/tmp/go-build3857722332/b496/config.test
/tmp/go-build3857722332/b496/config.test
-test.testlogfile=/tmp/go-build3857722332/b496/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -qui�� 4W2NdfqUv
/tmp/go-build175238182/b318/ ache/go/1.25.8/x64/pkg/tool/linu-importcfg
. -imultiarch x86_64-linux-gnu rtcfg -I o
aw-mcpg/internal/config/rules/rules_test.go x_amd64/compile --gdwarf-5
--64 -o x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build516878933/b492/config.test
/tmp/go-build516878933/b492/config.test
-test.testlogfile=/tmp/go-build516878933/b492/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
/tmp/go-build3857722332/b001/_pk/run/containerd/io.containerd.runtime.v2.task/moby/1aae6b0541c71bash
576e049387694a82674f762305209147fde512f1ff55f4537e6 e-handler
576e049387694a82/usr/bin/chronyc` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build175238182/b510/launcher.test
/tmp/go-build175238182/b510/launcher.test
-test.testlogfile=/tmp/go-build175238182/b510/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ache/go/1.25.8/x-errorsas cgo_.o 64/bin/as -p vendor/golang.or-atomic
-lang=go1.25 238182/b171/_x00-buildtags -p ity/connectivity-errorsas
-trimpath x_amd64/compile -I /tmp/go-build175docker-cli-plugin-metadata
-I x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build3857722332/b514/launcher.test
/tmp/go-build3857722332/b514/launcher.test
-test.testlogfile=/tmp/go-build3857722332/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s rtcf��
pkg/mod/google.golang.org/grpc@v1.80.0/binarylog-s tmain.go x_amd64/vet
/x64=/_/GOROOT --local u/13/cc1 x_amd64/vet -o /tmp/go-build175-errorsas
ettings.Ports}} x_amd64/vet -p go.opentelemetry--version -lang=go1.25
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build516878933/b510/launcher.test
/tmp/go-build516878933/b510/launcher.test
-test.testlogfile=/tmp/go-build516878933/b510/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
7722332/b559/tty.test -tests 7722332/b559/importcfg.link
8NDC/SRjZ7_MrzxIbash pkg/mod/go.opent/usr/bin/runc
ache/go/1.25.8/x--root 97a/log.json U02
io.containerd.ru/run/containerd/io.containerd.runtime.v2.task/moby/83fdf3a250dfab704055af7b451aa/usr/bin/runc.original
{{json .NetworkS--log-format che/go-build/ba/json
by/197def118f828/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
-importcfg x_amd64/vet runc` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build175238182/b510/launcher.test
/tmp/go-build175238182/b510/launcher.test
-test.testlogfile=/tmp/go-build175238182/b510/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ache/go/1.25.8/x-errorsas cgo_.o 64/bin/as -p vendor/golang.or-atomic
-lang=go1.25 238182/b171/_x00-buildtags -p ity/connectivity-errorsas
-trimpath x_amd64/compile -I /tmp/go-build175docker-cli-plugin-metadata
-I x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build3857722332/b514/launcher.test
/tmp/go-build3857722332/b514/launcher.test
-test.testlogfile=/tmp/go-build3857722332/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s rtcf��
pkg/mod/google.golang.org/grpc@v1.80.0/binarylog-s tmain.go x_amd64/vet
/x64=/_/GOROOT --local u/13/cc1 x_amd64/vet -o /tmp/go-build175-errorsas
ettings.Ports}} x_amd64/vet -p go.opentelemetry--version -lang=go1.25
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build516878933/b510/launcher.test
/tmp/go-build516878933/b510/launcher.test
-test.testlogfile=/tmp/go-build516878933/b510/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
7722332/b559/tty.test -tests 7722332/b559/importcfg.link
8NDC/SRjZ7_MrzxIbash pkg/mod/go.opent/usr/bin/runc
ache/go/1.25.8/x--root 97a/log.json U02
io.containerd.ru/run/containerd/io.containerd.runtime.v2.task/moby/83fdf3a250dfab704055af7b451aa/usr/bin/runc.original
{{json .NetworkS--log-format che/go-build/ba/json
by/197def118f828/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
-importcfg x_amd64/vet runc` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build175238182/b519/mcp.test
/tmp/go-build175238182/b519/mcp.test
-test.testlogfile=/tmp/go-build175238182/b519/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
s/known/fieldmaskpb/field_mask.pb.go @v1.43.0/semconv/v1.37.0/doc.go
x_amd64/compile --gdwarf-5 --64 -o x_amd64/compile 2381�� _.a
238182/b165/ x_amd64/vet --gdwarf-5 /v1.40.0 -o x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3857722332/b523/mcp.test
/tmp/go-build3857722332/b523/mcp.test
-test.testlogfile=/tmp/go-build3857722332/b523/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -o
/tmp/go-build175238182/b459/_pkg_.a -trimpath x_amd64/vet -p
github.com/githu-qE -lang=go1.25 x_amd64/vet -ato�� g_.a -buildtags
x_amd64/vet -errorsas ernal/logger -nilfunc x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build516878933/b519/mcp.test
/tmp/go-build516878933/b519/mcp.test
-test.testlogfile=/tmp/go-build516878933/b519/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true (create|run)
runtime-runc/mobjson` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 11, 2026
… WRITE_OPERATIONS (#3609)

Three GitHub CLI write operations had no guard coverage — meaning if a
corresponding MCP tool lands in github-mcp-server, it would pass through
unclassified. All three are high/medium risk operations involving repo
settings, PR reversion, and SSH key grants.

### `tools.rs` — WRITE_OPERATIONS additions
- `edit_repository` — `PATCH /repos/{owner}/{repo}`; can flip visibility
private→public
- `revert_pull_request` — GraphQL `revertPullRequest`; creates branch +
PR
- `add_deploy_key` / `delete_deploy_key` — `POST/DELETE
/repos/{owner}/{repo}/keys`; grants persistent SSH access

### `tool_rules.rs` — DIFC label rules
```rust
"edit_repository" => {
    secrecy = apply_repo_visibility_secrecy(&owner, &repo, repo_id, secrecy, ctx);
    integrity = writer_integrity(repo_id, ctx);
}
"revert_pull_request" => {
    secrecy = apply_repo_visibility_secrecy(&owner, &repo, repo_id, secrecy, ctx);
    integrity = writer_integrity(repo_id, ctx);
}
"add_deploy_key" | "delete_deploy_key" => {
    // Always private regardless of repo visibility — deploy key secrets are sensitive
    secrecy = policy_private_scope_label(&owner, &repo, repo_id, ctx);
    integrity = writer_integrity(repo_id, ctx);
}
```

Deploy key operations use `policy_private_scope_label` unconditionally
(not `apply_repo_visibility_secrecy`) since the key material itself is
always sensitive regardless of whether the repo is public.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build3092088994/b514/launcher.test
/tmp/go-build3092088994/b514/launcher.test
-test.testlogfile=/tmp/go-build3092088994/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -W .cfg
Bmen/MKrSXkkW-_Q-ifaceassert x_amd64/vet . --gdwarf2 --64 x_amd64/vet
9006�� .cfg olang.org/grpc@v1.80.0/internal/transport/client_stream.go
x_amd64/vet --gdwarf-5 g/grpc/attribute-qE -o x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3092088994/b496/config.test
/tmp/go-build3092088994/b496/config.test
-test.testlogfile=/tmp/go-build3092088994/b496/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build3092088994/b323/vet.cfg 5.0/deviceauth.g-errorsas
5.0/oauth2.go x_amd64/vet --gdwarf-5 nal/protolazy -o x_amd64/vet -I
g_.a -I x_amd64/vet --gdwarf-5 go-sdk/auth -o x_amd64/vet` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build3092088994/b514/launcher.test
/tmp/go-build3092088994/b514/launcher.test
-test.testlogfile=/tmp/go-build3092088994/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -W .cfg
Bmen/MKrSXkkW-_Q-ifaceassert x_amd64/vet . --gdwarf2 --64 x_amd64/vet
9006�� .cfg olang.org/grpc@v1.80.0/internal/transport/client_stream.go
x_amd64/vet --gdwarf-5 g/grpc/attribute-qE -o x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build3092088994/b514/launcher.test
/tmp/go-build3092088994/b514/launcher.test
-test.testlogfile=/tmp/go-build3092088994/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -W .cfg
Bmen/MKrSXkkW-_Q-ifaceassert x_amd64/vet . --gdwarf2 --64 x_amd64/vet
9006�� .cfg olang.org/grpc@v1.80.0/internal/transport/client_stream.go
x_amd64/vet --gdwarf-5 g/grpc/attribute-qE -o x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3092088994/b523/mcp.test
/tmp/go-build3092088994/b523/mcp.test
-test.testlogfile=/tmp/go-build3092088994/b523/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build3092088994/b517/_pkg_.a
elemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp@v1.43.0/internal/otlpconfig/envconfig.go/usr/bin/runc.original
elemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp@v1.43.0/internal/otlpconfig/options.go
x_amd64/vet --gdwarf-5 g/grpc/internal -o x_amd64/vet -obj�� .cfg
-importpath x_amd64/vet -ldflags=&#34;-O2&#34;
&#34;/usr/libexec/docker/docker-init ecosystem/grpc-g--version -I
x_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 12, 2026
…oor_from_str` (#3654)

Two match arms in `author_association_floor_from_str` both returned
`vec![]`, making `"FIRST_TIMER" | "NONE"` dead code — fully subsumed by
the wildcard below it.

## Changes

- **`guards/github-guard/rust-guard/src/labels/helpers.rs`**: Drop the
`"FIRST_TIMER" | "NONE"` arm; fold into the wildcard with a clarifying
comment.

```rust
// Before
"FIRST_TIMER" | "NONE" => vec![],
_ => vec![],

// After
_ => vec![], // FIRST_TIMER, NONE, or any unrecognised value
```

No behaviour change. The `lib.rs` duplicate integrity-branch issue noted
in the report was already resolved in the codebase.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build4291131586/b514/launcher.test
/tmp/go-build4291131586/b514/launcher.test
-test.testlogfile=/tmp/go-build4291131586/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s E=3 .cfg
/tmp/go-build406-ifaceassert x_amd64/vet . --gdwarf2 --64 x_amd64/vet
.cfg�� /yaml.v3@v3.0.1/apic.go /yaml.v3@v3.0.1/decode.go x_amd64/vet
ute.go mentation.go -o x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build4291131586/b496/config.test
/tmp/go-build4291131586/b496/config.test
-test.testlogfile=/tmp/go-build4291131586/b496/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build4291131586/b338/vet.cfg oding@v0.5.4/iso8601/parse.go
oding@v0.5.4/iso8601/valid.go x_amd64/vet --gdwarf-5 nal/protolazy -o
x_amd64/vet 4459�� g_.a ache/go/1.25.8/x64/src/log/log.go x_amd64/vet
--gdwarf-5 4459165/b239/ -o x_amd64/vet` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build4291131586/b514/launcher.test
/tmp/go-build4291131586/b514/launcher.test
-test.testlogfile=/tmp/go-build4291131586/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s E=3 .cfg
/tmp/go-build406-ifaceassert x_amd64/vet . --gdwarf2 --64 x_amd64/vet
.cfg�� /yaml.v3@v3.0.1/apic.go /yaml.v3@v3.0.1/decode.go x_amd64/vet
ute.go mentation.go -o x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build4291131586/b514/launcher.test
/tmp/go-build4291131586/b514/launcher.test
-test.testlogfile=/tmp/go-build4291131586/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s E=3 .cfg
/tmp/go-build406-ifaceassert x_amd64/vet . --gdwarf2 --64 x_amd64/vet
.cfg�� /yaml.v3@v3.0.1/apic.go /yaml.v3@v3.0.1/decode.go x_amd64/vet
ute.go mentation.go -o x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build4291131586/b523/mcp.test
/tmp/go-build4291131586/b523/mcp.test
-test.testlogfile=/tmp/go-build4291131586/b523/testlog.txt
-test.paniconexit0 -test.timeout=10m0s .cfg�� 4459165/b389/_pk-p -I
x_amd64/vet --gdwarf-5 g/grpc/internal//usr/bin/runc -o x_amd64/vet
.cfg�� lhk-/9CAufbOhYsrgo1.25.8 /tmp/go-build406-c=4 x_amd64/vet .
_value&#34;].&#34;\n&#34;; --64 x_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 15, 2026
… semantic analysis (#3897)

Three recurring code-quality findings from semantic function clustering
analysis: a near-duplicate pair across `server`/`proxy`, a misplaced
config validator, and a trivial one-liner wrapper.

## Changes

- **`internal/httputil`** — add shared `ParseRateLimitResetHeader(value
string) time.Time` with `strings.TrimSpace` normalization, replacing two
near-identical private implementations:
- `parseRateLimitResetHeader` in `internal/server/circuit_breaker.go`
(had `TrimSpace`)
- `parseRateLimitReset` in `internal/proxy/handler.go` (lacked
`TrimSpace`)

- **`internal/config/validation.go`** — move `validateGuardPolicies`
here from `guard_policy.go`; it takes `*Config` and belongs alongside
`validateGatewayConfig`, `validateTrustedBots`,
`validateOpenTelemetryConfig`, etc. Replace `logGuardPolicy` →
`logValidation`.

- **`internal/proxy/graphql.go`** — remove `truncateForLog` (a one-line
pass-through to `strutil.TruncateRunes`); inline
`strutil.TruncateRunes(s, 80)` directly at the two call sites,
consistent with the rest of the codebase.

## Test changes

- Added `TestParseRateLimitResetHeader` to `httputil_test.go` (includes
whitespace-trimming case).
- Removed `TestParseRateLimitResetHeader` from `circuit_breaker_test.go`
and `TestParseRateLimitReset` from `rate_limit_test.go` — now covered by
the shared test.
- Removed `graphql_test.go` (only contained `TestTruncateForLog`;
`strutil.TruncateRunes` is already tested in
`strutil/truncate_test.go`).

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build907643046/b514/launcher.test
/tmp/go-build907643046/b514/launcher.test
-test.testlogfile=/tmp/go-build907643046/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s .cfg�� 6809213/b405/_pk-errorsas
0L32/Gn657Kg8UZO-ifaceassert x_amd64/vet --gdwarf-5 /http2/hpack -o
x_amd64/vet .cfg�� lete: awmg&#34;
ache/go/1.25.8/x64/src/crypto/tls/alert.go x_amd64/vet . --gdwarf2 --64
x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build907643046/b496/config.test
/tmp/go-build907643046/b496/config.test
-test.testlogfile=/tmp/go-build907643046/b496/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build907643046/b395/vet.cfg /testutil/mcptesgo1.25.8
/testutil/mcptes-c=4 x_amd64/vet 6809213/b151/ -imultiarch
x86_64-linux-gnu-bool x_amd64/vet 6809�� g_.a
olang.org/grpc@v-ifaceassert 64/pkg/tool/linu-nilfunc . ce/tracetest
--64 64/pkg/tool/linu-buildtags` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build907643046/b514/launcher.test
/tmp/go-build907643046/b514/launcher.test
-test.testlogfile=/tmp/go-build907643046/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s .cfg�� 6809213/b405/_pk-errorsas
0L32/Gn657Kg8UZO-ifaceassert x_amd64/vet --gdwarf-5 /http2/hpack -o
x_amd64/vet .cfg�� lete: awmg&#34;
ache/go/1.25.8/x64/src/crypto/tls/alert.go x_amd64/vet . --gdwarf2 --64
x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build907643046/b514/launcher.test
/tmp/go-build907643046/b514/launcher.test
-test.testlogfile=/tmp/go-build907643046/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s .cfg�� 6809213/b405/_pk-errorsas
0L32/Gn657Kg8UZO-ifaceassert x_amd64/vet --gdwarf-5 /http2/hpack -o
x_amd64/vet .cfg�� lete: awmg&#34;
ache/go/1.25.8/x64/src/crypto/tls/alert.go x_amd64/vet . --gdwarf2 --64
x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build907643046/b523/mcp.test
/tmp/go-build907643046/b523/mcp.test
-test.testlogfile=/tmp/go-build907643046/b523/testlog.txt
-test.paniconexit0 -test.timeout=10m0s .cfg�� FM1m/LEd7bURSK2u2w4dcFM1m
/tmp/go-build1626809213/b288/ x_amd64/vet � Warning: golanrunc --gdwarf2
--64 x_amd64/vet .cfg�� 6184859/b100/vet.cfg -trimpath x_amd64/vet
lock.go lock_sort.go -lang=go1.19 x_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 17, 2026
…ken (#4026)

The scheduled Repo Assist run completed successfully but produced no
safe outputs, triggering a failure issue despite no runtime/job failure.
The workflow prompt allowed a “no action” outcome without explicitly
requiring a safe output artifact.

- **Root cause**
- Repo Assist guidance emphasized restraint and allowed “no action”
runs, but did not explicitly require emitting a safe output in that
branch.
- This permitted successful runs to end with empty safe outputs (`items:
[]`), which the conclusion stage treats as a failure condition.

- **Change**
- Updated `.github/workflows/repo-assist.md` with a strict safe-output
requirement:
- If the agent determines there is truly nothing useful to do, it must
emit **exactly one** `noop` safe output with a brief reason.
    - It must not end with empty safe outputs.

- **Behavioral impact**
- “No work this run” is now represented as an explicit, machine-readable
outcome (`noop`) instead of an empty output set.
- Preserves existing task-selection and action behavior; only clarifies
terminal behavior for the no-op path.

```md
**Safe output requirement**: Never end with empty safe outputs. If, after completing all required checks, you determine there is truly nothing useful to do this run, you must emit exactly one `noop` safe output with a brief reason (and no other safe outputs).
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build3960202725/b510/launcher.test
/tmp/go-build3960202725/b510/launcher.test
-test.testlogfile=/tmp/go-build3960202725/b510/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
1.10.2/active_help.go 1.10.2/args.go x_amd64/vet --gdwarf-5
pickfirst/intern-atomic -o x_amd64/vet --de�� g_.a
--debug-prefix-m-ifaceassert x_amd64/vet -g&#34; resolver/delegat-atomic
-I x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build2572188529/b514/launcher.test
/tmp/go-build2572188529/b514/launcher.test
-test.testlogfile=/tmp/go-build2572188529/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s 0163��
/tmp/go-build935016357/b094/vet.cfg
/home/REDACTED/go/pkg/mod/go.opentelemetry.io/otel-ifaceassert
64/pkg/tool/linux_amd64/vet acehttp@v1.43.0/git --local
/opt/hostedtoolc-v 64/pkg/tool/linuorigin` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3960202725/b492/config.test
/tmp/go-build3960202725/b492/config.test
-test.testlogfile=/tmp/go-build3960202725/b492/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true @v1.1.3/cpu/cpu.go
7008033/b151/ x_amd64/vet
/tmp/go-build352/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet
ternal/engine/wa-unsafeptr=false x86_64-linux-gnu-unreachable=false
x_amd64/vet 7008�� CsQlTmGwP -I x_amd64/vet --gdwarf-5 --64 -o
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build2572188529/b496/config.test
/tmp/go-build2572188529/b496/config.test
-test.testlogfile=/tmp/go-build2572188529/b496/testlog.txt
-test.paniconexit0 -test.timeout=10m0s 0163�� fy66OxATrrbMgUIjgo1.25.8
.cfg 64/pkg/tool/linu-nolocalimports -c=4 -nolocalimports -importcfg
64/pkg/tool/linuREDACTED 0163�� /tmp/go-build935016357/b094/vet.cfg
/home/REDACTED/go/pkg/mod/go.opentelemetry.io/otel-ifaceassert
64/pkg/tool/linux_amd64/vet acehttp@v1.43.0/git --local
/opt/hostedtoolc-v 64/pkg/tool/linuorigin` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build3960202725/b510/launcher.test
/tmp/go-build3960202725/b510/launcher.test
-test.testlogfile=/tmp/go-build3960202725/b510/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
1.10.2/active_help.go 1.10.2/args.go x_amd64/vet --gdwarf-5
pickfirst/intern-atomic -o x_amd64/vet --de�� g_.a
--debug-prefix-m-ifaceassert x_amd64/vet -g&#34; resolver/delegat-atomic
-I x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build2572188529/b514/launcher.test
/tmp/go-build2572188529/b514/launcher.test
-test.testlogfile=/tmp/go-build2572188529/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s 0163��
/tmp/go-build935016357/b094/vet.cfg
/home/REDACTED/go/pkg/mod/go.opentelemetry.io/otel-ifaceassert
64/pkg/tool/linux_amd64/vet acehttp@v1.43.0/git --local
/opt/hostedtoolc-v 64/pkg/tool/linuorigin` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build3960202725/b510/launcher.test
/tmp/go-build3960202725/b510/launcher.test
-test.testlogfile=/tmp/go-build3960202725/b510/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
1.10.2/active_help.go 1.10.2/args.go x_amd64/vet --gdwarf-5
pickfirst/intern-atomic -o x_amd64/vet --de�� g_.a
--debug-prefix-m-ifaceassert x_amd64/vet -g&#34; resolver/delegat-atomic
-I x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build2572188529/b514/launcher.test
/tmp/go-build2572188529/b514/launcher.test
-test.testlogfile=/tmp/go-build2572188529/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s 0163��
/tmp/go-build935016357/b094/vet.cfg
/home/REDACTED/go/pkg/mod/go.opentelemetry.io/otel-ifaceassert
64/pkg/tool/linux_amd64/vet acehttp@v1.43.0/git --local
/opt/hostedtoolc-v 64/pkg/tool/linuorigin` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3960202725/b519/mcp.test
/tmp/go-build3960202725/b519/mcp.test
-test.testlogfile=/tmp/go-build3960202725/b519/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true cfg
/tmp/go-build3527008033/b151/ x_amd64/vet 7008033/b288/
telabs/wazero/in/usr/bin/runc --64 x_amd64/vet cfg 7008033/b444/_pkg_.a
-I x_amd64/vet --gdwarf-5 ntio/asm/cpu -o x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build2572188529/b523/mcp.test
/tmp/go-build2572188529/b523/mcp.test
-test.testlogfile=/tmp/go-build2572188529/b523/testlog.txt
-test.paniconexit0 -test.timeout=10m0s` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 18, 2026
…ned patterns (#4051)

This PR addresses the Go Fan/testify review by replacing low-signal
assertion patterns with more specific testify assertions across the
reported test areas. The goal is to improve failure diagnostics and
align tests with current assertion best practices without changing
production behavior.

- **Assertion specificity cleanup**
  - Replaced boolean equality assertions with direct boolean assertions:
- `assert.Equal(t, true/false, ...)` → `assert.True(...)` /
`assert.False(...)`
  - Replaced generic substring checks:
    - `assert.True(t, strings.Contains(...))` → `assert.Contains(...)`
- `assert.False(t, strings.Contains(...))` → `assert.NotContains(...)`
  - Replaced length-comparison boolean assertions:
    - `assert.True(t, len(x) <= N)` → `assert.LessOrEqual(t, len(x), N)`
- Replaced one compound substring OR check with `assert.Regexp(...)` for
direct intent.

- **Typed-nil error assertion handling in `rules_test.go`**
- The five `require.Nil(t, err)` sites were updated to
`require.NoError(...)` semantics while preserving behavior for typed-nil
`*ValidationError` returns.
  - Added a tiny adapter helper used only in tests:
    - `validationErrAsError(err *ValidationError) error`

- **Test import cleanup**
- Removed now-unused `strings` imports in files where
`assert.Contains`/`assert.NotContains` replaced manual
`strings.Contains` calls.

```go
// Before
assert.True(t, strings.Contains(text, "Bug report"), "response text should contain the issue title")

// After
assert.Contains(t, text, "Bug report", "response text should contain the issue title")
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build850057972/b514/launcher.test
/tmp/go-build850057972/b514/launcher.test
-test.testlogfile=/tmp/go-build850057972/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s E=3 .cfg /tmp/go-build403-w
x_amd64/vet . --gdwarf2 --64 x_amd64/vet -I .cfg
TiyY/dyEj6sNqXXBEEx-BTiyY x_amd64/vet --gdwarf-5 g/grpc/internal/-qE -o
x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build850057972/b496/config.test
/tmp/go-build850057972/b496/config.test
-test.testlogfile=/tmp/go-build850057972/b496/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build850057972/b394/vet.cfg @v1.1.3/cpu/x86/-errorsas -I
x_amd64/vet --gdwarf-5 .io/otel/baggage-atomic -o x_amd64/vet 2483��
g_.a L_XeGB1fo x_amd64/vet -p vendor/golang.or-atomic -lang=go1.25
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build772277680/b224/config.test
/tmp/go-build772277680/b224/config.test
-test.testlogfile=/tmp/go-build772277680/b224/testlog.txt
-test.paniconexit0 -test.timeout=10m0s rtcf�� by/280457505e8d1REDACTED y
ache/go/1.25.8/x64/pkg/tool/linujson
ntime.v2.task/mo/usr/libexec/docker/cli-plugins/docker-buildx
-ifaceassert -nilfunc ache/go/1.25.8/x64/pkg/tool/linu--no-legend
&#34;SSL�� ef5286be851aaba1bad991c168a5fac9-- -tests
ker/cli-plugins/docker-compose by/c68777e185eb8node
ache/go/1.25.8/xmock-mcp-server.js x_amd64/vet fce/log.json` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build850057972/b514/launcher.test
/tmp/go-build850057972/b514/launcher.test
-test.testlogfile=/tmp/go-build850057972/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s E=3 .cfg /tmp/go-build403-w
x_amd64/vet . --gdwarf2 --64 x_amd64/vet -I .cfg
TiyY/dyEj6sNqXXBEEx-BTiyY x_amd64/vet --gdwarf-5 g/grpc/internal/-qE -o
x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build850057972/b514/launcher.test
/tmp/go-build850057972/b514/launcher.test
-test.testlogfile=/tmp/go-build850057972/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s E=3 .cfg /tmp/go-build403-w
x_amd64/vet . --gdwarf2 --64 x_amd64/vet -I .cfg
TiyY/dyEj6sNqXXBEEx-BTiyY x_amd64/vet --gdwarf-5 g/grpc/internal/-qE -o
x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build850057972/b523/mcp.test
/tmp/go-build850057972/b523/mcp.test
-test.testlogfile=/tmp/go-build850057972/b523/testlog.txt
-test.paniconexit0 -test.timeout=10m0s .cfg�� 2483721/b343/_pkg_.a -fPIC
x_amd64/vet us.pb.go g/grpc/balancer -fmessage-length=0 x_amd64/vet
.cfg�� /oidc/errors.go /oidc/provider.go x_amd64/vet -dynout
g/grpc/health/gr/usr/bin/runc -ffile-prefix-ma--version x_amd64/vet`
(dns block)
> - Triggering command: `/tmp/go-build772277680/b484/mcp.test
/tmp/go-build772277680/b484/mcp.test
-test.testlogfile=/tmp/go-build772277680/b484/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -ato�� -bool y
etc/ssl/certs/ca-certificates.crt&#34;,
&#34;REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certifi 3cfebab8779a2365/check
-ifaceassert -nilfunc noffline 287f��
ef5286be851aaba1bad991c168a5fac9/run/containerd/io.containerd.runtime.v2.task/moby/5878ee59bbb48go
3cfebab8779a2365c0a0927369ddf64be3c02162ae57d53bf27 /usr/bin/grep
9381bd4d1eab940e/usr/bin/runc.original` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 18, 2026
…sponse logging (#4106)

Recent `SendRequestWithServerID` cleanup left three duplication/safety
gaps: repeated marshal-for-debug blocks, duplicated sys tool handler
skeletons, and unsanitized `sys_list_servers` result logging. This PR
consolidates those paths and closes the sanitization gap.

- **Consolidate marshal-for-debug logic**
- Added `logger.LogMarshaledForDebug(...)` in
`internal/logger/marshal_debug.go`.
  - Replaced repeated marshal+error/success logging blocks in:
    - `internal/guard/wasm.go`
    - `internal/server/guard_init.go`
- Result: one shared marshaling pattern for debug logging across
guard/server paths.

- **Unify sys tool call/error/log skeleton**
- Added `callAndLogSysTool(...)` in `internal/server/tool_registry.go`.
- `sysInitHandler` and `sysListHandler` now share one call path (call
sys server → handle error → marshal/log result → return).

- **Fix sanitization gap in `sys_list_servers` logging**
  - Added shared `marshalAndSanitizeForLog(...)` in `tool_registry.go`.
- `sys_list_servers` response logs now use
`sanitize.SanitizeString(...)`, matching `sys_init` and backend tool
logging behavior.

- **Focused test coverage**
  - Added helper tests for marshal debug utility:
    - `internal/logger/marshal_debug_test.go`
  - Added server tests for log sanitization/error behavior:
    - `internal/server/tool_registry_test.go`

```go
func (us *UnifiedServer) callAndLogSysTool(sessionID, operationName, sysToolName string) (*sdk.CallToolResult, interface{}, error) {
	result, err := us.callSysServer(sysToolName)
	if err != nil {
		logger.LogError("client", "MCP %s call failed, session=%s, error=%v", operationName, sessionID, err)
		return mcp.NewErrorCallToolResult(err)
	}
	logger.LogInfo("client", "MCP %s response, session=%s, result=%s", operationName, sessionID, marshalAndSanitizeForLog(result))
	return nil, result, nil
}
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build1793350213/b510/launcher.test
/tmp/go-build1793350213/b510/launcher.test
-test.testlogfile=/tmp/go-build1793350213/b510/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
3350213/b184/_pk-errorsas 64/src/log/slog/-ifaceassert bin/as -p
zevo/backend/isa-atomic -lang=go1.25 /opt/hostedtoolc-buildtags -o
s/attributes.go idRS/k9xnSFeesAm-ifaceassert x_amd64/compile -p
crypto/internal/info -lang=go1.25 x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build3990767025/b514/launcher.test
/tmp/go-build3990767025/b514/launcher.test
-test.testlogfile=/tmp/go-build3990767025/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build3990767025/b495/vet.cfg ry=1 -trimpath x_amd64/vet -p
github.com/githupush -lang=go1.25 x_amd64/vet -ato�� .cfg -buildtags
64/pkg/tool/linux_amd64/vet -errorsas -ifaceassert -nilfunc
64/pkg/tool/linu-trimpath` (dns block)
> - Triggering command: `/tmp/go-build848674421/b514/launcher.test
/tmp/go-build848674421/b514/launcher.test
-test.testlogfile=/tmp/go-build848674421/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s know��
l/server/tool_registry_test.go
known-linux-gnu/lib/rustlib/x86_--format=format:%H %ct %D
stable-x86_64-REDACTED-linux-gnu/--end-of-options 6e1dc71b.rlib ccc.rlib
--systemd-cgroup-bool` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1793350213/b492/config.test
/tmp/go-build1793350213/b492/config.test
-test.testlogfile=/tmp/go-build1793350213/b492/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 3350213/b151/_pk-p o
x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build3990767025/b496/config.test
/tmp/go-build3990767025/b496/config.test
-test.testlogfile=/tmp/go-build3990767025/b496/testlog.txt
-test.paniconexit0 -test.timeout=10m0s n-me�� g_.a
pkg/mod/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp@v1.43.0/doc.go
x_amd64/vet -p github.com/segme--norc -lang=go1.17 x_amd64/vet -ato��
MQJZCSQ0B -buildtags x_amd64/vet -errorsas -ifaceassert -nilfunc
ks...&#34;; \
elif c--revs` (dns block)
> - Triggering command: `/tmp/go-build848674421/b496/config.test
/tmp/go-build848674421/b496/config.test
-test.testlogfile=/tmp/go-build848674421/b496/testlog.txt
-test.paniconexit0 -test.timeout=10m0s 05ed�� 05ed-cgu.10.rcgu-errorsas
05ed-cgu.11.rcgu-ifaceassert 05ed-cgu.12.rcgu-nilfunc
05ed-cgu.13.rcgugit 05ed-cgu.14.rcguls-files
pt_build-842ae9a--exclude-standard pt_build-842ae9a--others /usr��
--root .rlib 6b2b26a06.rlib 327.rlib 653.rlib 86b29d.rlib
ive.12123747d8da05ed-cgu.00.rcgu.o` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build1793350213/b510/launcher.test
/tmp/go-build1793350213/b510/launcher.test
-test.testlogfile=/tmp/go-build1793350213/b510/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
3350213/b184/_pk-errorsas 64/src/log/slog/-ifaceassert bin/as -p
zevo/backend/isa-atomic -lang=go1.25 /opt/hostedtoolc-buildtags -o
s/attributes.go idRS/k9xnSFeesAm-ifaceassert x_amd64/compile -p
crypto/internal/info -lang=go1.25 x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build3990767025/b514/launcher.test
/tmp/go-build3990767025/b514/launcher.test
-test.testlogfile=/tmp/go-build3990767025/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build3990767025/b495/vet.cfg ry=1 -trimpath x_amd64/vet -p
github.com/githupush -lang=go1.25 x_amd64/vet -ato�� .cfg -buildtags
64/pkg/tool/linux_amd64/vet -errorsas -ifaceassert -nilfunc
64/pkg/tool/linu-trimpath` (dns block)
> - Triggering command: `/tmp/go-build848674421/b514/launcher.test
/tmp/go-build848674421/b514/launcher.test
-test.testlogfile=/tmp/go-build848674421/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s know��
l/server/tool_registry_test.go
known-linux-gnu/lib/rustlib/x86_--format=format:%H %ct %D
stable-x86_64-REDACTED-linux-gnu/--end-of-options 6e1dc71b.rlib ccc.rlib
--systemd-cgroup-bool` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build1793350213/b510/launcher.test
/tmp/go-build1793350213/b510/launcher.test
-test.testlogfile=/tmp/go-build1793350213/b510/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
3350213/b184/_pk-errorsas 64/src/log/slog/-ifaceassert bin/as -p
zevo/backend/isa-atomic -lang=go1.25 /opt/hostedtoolc-buildtags -o
s/attributes.go idRS/k9xnSFeesAm-ifaceassert x_amd64/compile -p
crypto/internal/info -lang=go1.25 x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build3990767025/b514/launcher.test
/tmp/go-build3990767025/b514/launcher.test
-test.testlogfile=/tmp/go-build3990767025/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build3990767025/b495/vet.cfg ry=1 -trimpath x_amd64/vet -p
github.com/githupush -lang=go1.25 x_amd64/vet -ato�� .cfg -buildtags
64/pkg/tool/linux_amd64/vet -errorsas -ifaceassert -nilfunc
64/pkg/tool/linu-trimpath` (dns block)
> - Triggering command: `/tmp/go-build848674421/b514/launcher.test
/tmp/go-build848674421/b514/launcher.test
-test.testlogfile=/tmp/go-build848674421/b514/testlog.txt
-test.paniconexit0 -test.timeout=10m0s know��
l/server/tool_registry_test.go
known-linux-gnu/lib/rustlib/x86_--format=format:%H %ct %D
stable-x86_64-REDACTED-linux-gnu/--end-of-options 6e1dc71b.rlib ccc.rlib
--systemd-cgroup-bool` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1793350213/b519/mcp.test
/tmp/go-build1793350213/b519/mcp.test
-test.testlogfile=/tmp/go-build1793350213/b519/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
transport/bdp_estimator.go transport/client_stream.go x_amd64/compile
-pthread e/otlptracehttp/--version -fmessage-length=0 x_amd64/compile
3350�� g_.a 3350213/b165/ x_amd64/vet --gdwarf-5 mcpgodebug -o
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3990767025/b523/mcp.test
/tmp/go-build3990767025/b523/mcp.test
-test.testlogfile=/tmp/go-build3990767025/b523/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -ato�� .cfg -buildtags
0278e5566a20dc05-d -errorsas -ifaceassert -nilfunc
64/pkg/tool/linu-buildtags --ve�� .cfg -tests 64/pkg/tool/linu-nilfunc
1024825-9d38bb40/usr/bin/runc.original toml@v1.6.0/depr--version
x_amd64/compile 64/pkg/tool/linu-tests` (dns block)
> - Triggering command: `/tmp/go-build848674421/b523/mcp.test
/tmp/go-build848674421/b523/mcp.test
-test.testlogfile=/tmp/go-build848674421/b523/testlog.txt
-test.paniconexit0 -test.timeout=10m0s ogpt�� q7jvxzdnkys32nfz-errorsas
0ok7l9sshaaz07e8-ifaceassert hw1mmy6a1aekmmsh-nilfunc
4p2kq4dabhq5b2kedocker wmuqycv01jbjtq95inspect ntained/cc
stable-x86_64-un{{.Config.OpenStdin}} stab��
stable-x86_64-REDACTED-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libobject-926daa94a00ee/usr/libexec/docker/docker-init
stable-x86_64-REDACTED-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libmemchr-48d5b0db80402--version
.1/x64/codeql/tools/linux64/java/lib/jspawnhelper
stable-x86_64-un/usr/libexec/docker/cli-plugins/docker-compose
7a5585.0r6f2y9pmdocker-cli-plugin-metadata
7a5585.0y8i0suihruczucboywd9kbz6/tmp/go-build985941549/b001/_pkg_.a
.1/x64/codeql/tools/linux64/java-trimpath` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 20, 2026
…d response path labeling coverage (#4212)

This PR addresses two gaps in the Rust guard: avoid per-call heap
allocation for output fields that are always static literals, and add
direct unit coverage for high-impact `label_response_paths` branches
(`search_repositories`, `list_pull_requests`, query-scoped
`search_issues`, and unknown-tool fallback).

- **Static output fields: `String` → `&'static str` (allocation
removal)**
- Updated `LabelResourceOutput::operation` and
`LabelAgentOutput::difc_mode` to `&'static str`.
- Removed redundant `.to_string()` at construction sites in
`label_resource` and `label_agent`.

- **Response path labeling tests (new coverage in `response_paths.rs`)**
  - Added tests to verify:
    - private vs public secrecy behavior for `search_repositories`
    - merged-integrity assignment for merged PRs in `list_pull_requests`
- repo-scope extraction from `repo:` query qualifier for `search_issues`
    - `None` result for unknown tools

- **Representative change**
  ```rust
  #[derive(Debug, Serialize)]
  struct LabelAgentOutput {
      agent: AgentLabels,
      difc_mode: &'static str,
      normalized_policy: NormalizedPolicy,
  }

  let output = LabelAgentOutput {
      agent: AgentLabels { secrecy, integrity },
      difc_mode: DIFC_MODE,
      normalized_policy,
  };
  ```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build1015159776/b513/launcher.test
/tmp/go-build1015159776/b513/launcher.test
-test.testlogfile=/tmp/go-build1015159776/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1015159776/b431/vet.cfg
1.80.0/health/grpc_health_v1/health.pb.go
1.80.0/health/grpc_health_v1/health_grpc.pb.go x_amd64/vet -p base
-lang=go1.25 x_amd64/vet -I g_.a 999199174/b287//-ifaceassert
x_amd64/vet --gdwarf-5 ernal/middleware-atomic 9199174/b287/
x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1015159776/b495/config.test
/tmp/go-build1015159776/b495/config.test
-test.testlogfile=/tmp/go-build1015159776/b495/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1015159776/b388/vet.cfg @v1.1.3/cpu/arm/go1.25.9
9199174/b151/ x_amd64/vet -p nal/impl -lang=go1.25 x_amd64/vet 9199��
g_.a -I x_amd64/vet --gdwarf-5 64 -o x_amd64/vet` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build1015159776/b513/launcher.test
/tmp/go-build1015159776/b513/launcher.test
-test.testlogfile=/tmp/go-build1015159776/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1015159776/b431/vet.cfg
1.80.0/health/grpc_health_v1/health.pb.go
1.80.0/health/grpc_health_v1/health_grpc.pb.go x_amd64/vet -p base
-lang=go1.25 x_amd64/vet -I g_.a 999199174/b287//-ifaceassert
x_amd64/vet --gdwarf-5 ernal/middleware-atomic 9199174/b287/
x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build1015159776/b513/launcher.test
/tmp/go-build1015159776/b513/launcher.test
-test.testlogfile=/tmp/go-build1015159776/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1015159776/b431/vet.cfg
1.80.0/health/grpc_health_v1/health.pb.go
1.80.0/health/grpc_health_v1/health_grpc.pb.go x_amd64/vet -p base
-lang=go1.25 x_amd64/vet -I g_.a 999199174/b287//-ifaceassert
x_amd64/vet --gdwarf-5 ernal/middleware-atomic 9199174/b287/
x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1015159776/b522/mcp.test
/tmp/go-build1015159776/b522/mcp.test
-test.testlogfile=/tmp/go-build1015159776/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -I .cfg
om/spf13/cobra@v1.10.2/args.go x_amd64/vet --gdwarf-5 g/grpc/resolver -o
x_amd64/vet .cfg�� 9199174/b394/_pkg_.a -importpath x_amd64/vet
-ldflags=&#34;-O2&#34; &#34;bash g/grpc/internal//usr/bin/runc -I
x_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 20, 2026
… and tighten logging semantics (#4213)

Semantic clustering flagged four targeted refactor opportunities:
duplicated tracer fallback logic, misplaced shared logger dispatch
state, unnecessary markdown logging indirection, and unclear
marshal-error handling in a logging helper. This PR consolidates those
seams without changing external behavior.

- **Tracer fallback deduplicated (`internal/tracing`, `internal/proxy`,
`internal/server`)**
- Added `tracing.GetCachedOrGlobal(cached trace.Tracer)` as the single
fallback path.
- Replaced duplicated `getTracer()` implementations in `proxyHandler`
and `UnifiedServer` with one-line calls to the shared helper.

- **`logFuncs` ownership moved to `common.go` (`internal/logger`)**
- Relocated shared `LogLevel -> function` dispatch map from
`file_logger.go` to `common.go`.
- Co-located implementation with the existing design guidance and
updated references to the new source location.

- **Markdown logging helper flow simplified
(`internal/logger/markdown_logger.go`)**
  - Removed `logWithMarkdownLevel` indirection.
- Updated `logWithMarkdown` to resolve `logFuncs[level]` internally,
reducing one helper layer and tightening call flow for `Log*Md`
wrappers.

- **Marshal helper intent made explicit
(`internal/server/tool_registry.go`)**
- Documented `marshalAndSanitizeForLog` as best-effort logging behavior
when JSON marshaling fails (sanitized empty-string fallback by design).

```go
// internal/tracing/provider.go
func GetCachedOrGlobal(cached trace.Tracer) trace.Tracer {
	if cached != nil {
		return cached
	}
	return Tracer()
}
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build1164881766/b513/launcher.test
/tmp/go-build1164881766/b513/launcher.test
-test.testlogfile=/tmp/go-build1164881766/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1164881766/b437/vet.cfg _.a go x_amd64/vet --gdwarf-5 --64
-o x_amd64/vet -E mBfaT_lUZ 544961/b287/ x_amd64/vet -I . -imultiarch
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3536398537/b513/launcher.test
/tmp/go-build3536398537/b513/launcher.test
-test.testlogfile=/tmp/go-build3536398537/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s list��
ithub-guard/rust-guard/target/de/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/link
s

Agent-Logs-Url: REDACTED
ithub-guard/rust-guard/target/de/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust/tmp/go-build3536398537/b507/guard.test
Ld/symbols.o 437f known-linux-gnu/-bool known-linux-gnu/-buildtags
know�� known-linux-gnu/-errorsas known-linux-gnu/-ifaceassert
known-linux-gnu/-nilfunc known-linux-gnu/bash
known-linux-gnu//usr/bin/runc known-linux-gnu/--version
known-linux-gnu/-tests` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1164881766/b495/config.test
/tmp/go-build1164881766/b495/config.test
-test.testlogfile=/tmp/go-build1164881766/b495/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1164881766/b395/vet.cfg /http2/ascii.go /http2/ciphers.go
x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet --de�� _.a zhqG-0L32
x_amd64/vet -I` (dns block)
> - Triggering command: `/tmp/go-build3536398537/b495/config.test
/tmp/go-build3536398537/b495/config.test
-test.testlogfile=/tmp/go-build3536398537/b495/testlog.txt
-test.paniconexit0 -test.timeout=10m0s lib/��
lib/rustlib/x86_/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/debash
lib/rustlib/x86_/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/de--norc
lib/rustlib/x86_/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/de--noprofile
lib/rustlib/x86_git lib/rustlib/x86_checkout
lib/rustlib/x86_copilot/refactor-semantic-function-clustering
lib/rustlib/x86_/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/debug/deps/github_guard-57d41235e07a5585.53ehv5r2twmuqycv01jbjtq95.19dllou.rcgu.o
lib/��
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libminiz_oxide-2b6a8d2f6e1dc71b.rlib
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libadler2-39ffdbc27c978ccc.rlib

&#34;CURL_CA_BUNDLE=//home/REDACTED/.rustup/toolchains/stable-x86_64-REDACTED-linux-gnu/echo
&#34;&#34; c1063f.rlib .cfg` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build1164881766/b513/launcher.test
/tmp/go-build1164881766/b513/launcher.test
-test.testlogfile=/tmp/go-build1164881766/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1164881766/b437/vet.cfg _.a go x_amd64/vet --gdwarf-5 --64
-o x_amd64/vet -E mBfaT_lUZ 544961/b287/ x_amd64/vet -I . -imultiarch
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3536398537/b513/launcher.test
/tmp/go-build3536398537/b513/launcher.test
-test.testlogfile=/tmp/go-build3536398537/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s list��
ithub-guard/rust-guard/target/de/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/link
s

Agent-Logs-Url: REDACTED
ithub-guard/rust-guard/target/de/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust/tmp/go-build3536398537/b507/guard.test
Ld/symbols.o 437f known-linux-gnu/-bool known-linux-gnu/-buildtags
know�� known-linux-gnu/-errorsas known-linux-gnu/-ifaceassert
known-linux-gnu/-nilfunc known-linux-gnu/bash
known-linux-gnu//usr/bin/runc known-linux-gnu/--version
known-linux-gnu/-tests` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build1164881766/b513/launcher.test
/tmp/go-build1164881766/b513/launcher.test
-test.testlogfile=/tmp/go-build1164881766/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1164881766/b437/vet.cfg _.a go x_amd64/vet --gdwarf-5 --64
-o x_amd64/vet -E mBfaT_lUZ 544961/b287/ x_amd64/vet -I . -imultiarch
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3536398537/b513/launcher.test
/tmp/go-build3536398537/b513/launcher.test
-test.testlogfile=/tmp/go-build3536398537/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s list��
ithub-guard/rust-guard/target/de/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/link
s

Agent-Logs-Url: REDACTED
ithub-guard/rust-guard/target/de/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust/tmp/go-build3536398537/b507/guard.test
Ld/symbols.o 437f known-linux-gnu/-bool known-linux-gnu/-buildtags
know�� known-linux-gnu/-errorsas known-linux-gnu/-ifaceassert
known-linux-gnu/-nilfunc known-linux-gnu/bash
known-linux-gnu//usr/bin/runc known-linux-gnu/--version
known-linux-gnu/-tests` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1164881766/b522/mcp.test
/tmp/go-build1164881766/b522/mcp.test
-test.testlogfile=/tmp/go-build1164881766/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -o cfg
om/modelcontextprotocol/go-sdk@v1.5.0/mcp/cmd.go x_amd64/vet -p
g/grpc/internal/--version -lang=go1.25 x_amd64/vet cfg /auth/header.go
/auth/header_test.go x_amd64/vet -c /cobra /tmp/go-build945544961/b287/
dWtd0aB/LlpLOT-ZzUhjnWEpG9lp` (dns block)
> - Triggering command: `/tmp/go-build3536398537/b522/mcp.test
/tmp/go-build3536398537/b522/mcp.test
-test.testlogfile=/tmp/go-build3536398537/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s know��
known-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libobject-926daa94a00ee327.rlib
known-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libmemchr-48d5b0db80402653.rlib
known-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libaddr2line-3367f26bd486b29d.rlib
known-linux-gnu/bash known-linux-gnu//usr/bin/runc
known-linux-gnu/--version ive.12123747d8da05ed-cgu.00.rcgu.o ive.��
ive.12123747d8da05ed-cgu.02.rcgu.o ive.12123747d8da05ed-cgu.03.rcgu.o
ive.12123747d8da05ed-cgu.04.rcgu.o
ive.12123747d8da/usr/libexec/docker/cli-plugins/docker-buildx
ive.12123747d8dadocker-cli-plugin-metadata
ive.12123747d8da05ed-cgu.07.rcgu/tmp/go-build3867419718/b001/exe/a.out
ive.12123747d8da05ed-cgu.08.rcgu-importcfg` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 22, 2026
…on canaries (#4302)

This updates the go-sdk integration points highlighted in the review:
production pagination now fails fast on cyclical cursors, and
upgrade-sensitive behavior around tool registration is covered by a
stronger canary. It also clarifies transport-specific protocol/session
handling to reduce future maintenance ambiguity.

- **Pagination safety in `internal/mcp/connection.go`**
- Added cursor-cycle detection to `paginateAll` using a `seenCursors`
set.
- Returns an explicit error when a backend repeats a cursor instead of
continuing until the page cap.

- **Pagination behavior coverage in `internal/mcp/connection_test.go`**
- Added a cycle-focused test case to `TestPaginateAll` that verifies
early termination on repeated cursors.
- Adjusted the max-pages test to use unique cursors so it continues
validating the cap path independently.

- **Transport-scope clarity in `internal/mcp/http_transport.go`**
- Clarified that `MCPProtocolVersion` applies to the plain JSON-RPC
fallback path only.
- Added inline rationale in `isSessionNotFoundError` for string fallback
matching when SDK typed errors are unavailable.

- **SDK-upgrade canary for schema-validation bypass in
`internal/server/routed_test.go`**
- Extended `TestRegisterToolWithoutValidation` with a strict-schema tool
and intentionally schema-invalid arguments.
- Verifies the `registerToolWithoutValidation`/`Server.AddTool` path
still invokes handlers without SDK argument-value validation
regressions.

```go
seenCursors := make(map[string]struct{})
for pageCount := 1; cursor != ""; pageCount++ {
    if _, seen := seenCursors[cursor]; seen {
        return nil, fmt.Errorf("list%s: backend serverID=%s returned cyclical cursor %q", itemKind, serverID, cursor)
    }
    seenCursors[cursor] = struct{}{}
    // fetch next page...
}
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build2010847725/b513/launcher.test
/tmp/go-build2010847725/b513/launcher.test
-test.testlogfile=/tmp/go-build2010847725/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2010847725/b423/vet.cfg
rotocol/go-sdk@v1.5.0/jsonrpc/jsonrpc.go -trimpath x_amd64/vet gci-lint
failed /opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linux_amd64/vet
7457537/b209/sym-atomic -lang=go1.25 x_amd64/vet -p g_.a
477457537/b287//-ifaceassert x_amd64/vet -I go-sdk/mcp 7457537/b287/
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build81877103/b513/launcher.test
/tmp/go-build81877103/b513/launcher.test
-test.testlogfile=/tmp/go-build81877103/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s rds/��
lib/rustlib/x86_/home/REDACTED/.rustup/toolchains/stable-x86_64-REDACTED-linux-gnu/lib/rustlib/x86_git
lib/rustlib/x86_/home/REDACTED/.rustup/toolchains/stable-x86_64-REDACTED-linux-gnu/lib/rustlib/x86_commit
-guard/target/debug/deps/rustco0oSqi/symbols.o -guard/target/debash b0d7
-guard/target/de--noprofile
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.03.rcgu.o
-gua��
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.05.rcgu/opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linux_amd64/vet
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.06.rcgu/tmp/go-build3709670566/b506/vet.cfg
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.07.rcgu.o
-guard/target/debash -guard/target/de--norc -guard/target/de--noprofile
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.11.rcgu.o`
(dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2010847725/b495/config.test
/tmp/go-build2010847725/b495/config.test
-test.testlogfile=/tmp/go-build2010847725/b495/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2010847725/b397/vet.cfg @v1.1.3/cpu/x86/-c=4
ggXp/9qGZEHgmklo-nolocalimports x_amd64/vet --gdwarf-5
nal/encoding/tag-atomic -o x_amd64/vet 7457�� g_.a
ache/go/1.25.9/x-ifaceassert x_amd64/vet -I /opt/hostedtoolc-atomic -I
x_amd64/vet` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build2010847725/b513/launcher.test
/tmp/go-build2010847725/b513/launcher.test
-test.testlogfile=/tmp/go-build2010847725/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2010847725/b423/vet.cfg
rotocol/go-sdk@v1.5.0/jsonrpc/jsonrpc.go -trimpath x_amd64/vet gci-lint
failed /opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linux_amd64/vet
7457537/b209/sym-atomic -lang=go1.25 x_amd64/vet -p g_.a
477457537/b287//-ifaceassert x_amd64/vet -I go-sdk/mcp 7457537/b287/
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build81877103/b513/launcher.test
/tmp/go-build81877103/b513/launcher.test
-test.testlogfile=/tmp/go-build81877103/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s rds/��
lib/rustlib/x86_/home/REDACTED/.rustup/toolchains/stable-x86_64-REDACTED-linux-gnu/lib/rustlib/x86_git
lib/rustlib/x86_/home/REDACTED/.rustup/toolchains/stable-x86_64-REDACTED-linux-gnu/lib/rustlib/x86_commit
-guard/target/debug/deps/rustco0oSqi/symbols.o -guard/target/debash b0d7
-guard/target/de--noprofile
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.03.rcgu.o
-gua��
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.05.rcgu/opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linux_amd64/vet
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.06.rcgu/tmp/go-build3709670566/b506/vet.cfg
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.07.rcgu.o
-guard/target/debash -guard/target/de--norc -guard/target/de--noprofile
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.11.rcgu.o`
(dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build2010847725/b513/launcher.test
/tmp/go-build2010847725/b513/launcher.test
-test.testlogfile=/tmp/go-build2010847725/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2010847725/b423/vet.cfg
rotocol/go-sdk@v1.5.0/jsonrpc/jsonrpc.go -trimpath x_amd64/vet gci-lint
failed /opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linux_amd64/vet
7457537/b209/sym-atomic -lang=go1.25 x_amd64/vet -p g_.a
477457537/b287//-ifaceassert x_amd64/vet -I go-sdk/mcp 7457537/b287/
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build81877103/b513/launcher.test
/tmp/go-build81877103/b513/launcher.test
-test.testlogfile=/tmp/go-build81877103/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s rds/��
lib/rustlib/x86_/home/REDACTED/.rustup/toolchains/stable-x86_64-REDACTED-linux-gnu/lib/rustlib/x86_git
lib/rustlib/x86_/home/REDACTED/.rustup/toolchains/stable-x86_64-REDACTED-linux-gnu/lib/rustlib/x86_commit
-guard/target/debug/deps/rustco0oSqi/symbols.o -guard/target/debash b0d7
-guard/target/de--noprofile
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.03.rcgu.o
-gua��
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.05.rcgu/opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linux_amd64/vet
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.06.rcgu/tmp/go-build3709670566/b506/vet.cfg
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.07.rcgu.o
-guard/target/debash -guard/target/de--norc -guard/target/de--noprofile
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.11.rcgu.o`
(dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2010847725/b522/mcp.test
/tmp/go-build2010847725/b522/mcp.test
-test.testlogfile=/tmp/go-build2010847725/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s abis�� cfg -I x_amd64/vet
--gdwarf-5 ce -o x_amd64/vet cfg 7457537/b449/_pkg_.a
nLJk/a4JpKmHiBmr_E514nLJk x_amd64/vet --gdwarf-5 ntio/asm/keyset -o
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build81877103/b522/mcp.test
/tmp/go-build81877103/b522/mcp.test
-test.testlogfile=/tmp/go-build81877103/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s lib/��
lib/rustlib/x86_/home/REDACTED/.rustup/toolchains/stable-x86_64-REDACTED-linux-gnu/lib/rustlib/x86_git
lib/rustlib/x86_/home/REDACTED/.rustup/toolchains/stable-x86_64-REDACTED-linux-gnu/lib/rustlib/x86_commit
lib/rustlib/x86_/home/REDACTED/.rustup/toolchains/stable-x86_64-REDACTED-linux-gnu/lib/rustlib/x86_-m
lib/rustlib/x86_bash b0d7 lib/rustlib/x86_--noprofile
lib/rustlib/x86_/home/REDACTED/.rustup/toolchains/stable-x86_64-REDACTED-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libminiz_oxide-2b6a8d2f6e1dc71b.rlib
lib/��
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/librustc_std_workspace_alloc-76b5fe9328c1063f.rlib
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libminiz_oxide-2b6a8d2f6e1dc71b.rlib
iginal -f &#34;$GOPATH/bin/bash -I yload_StoredInPa--noprofile
-guard/target/debug/deps/libserde_derive-bdc7cd22a58a5141.so` (dns
block)
> - Triggering command: `/tmp/go-build1985989918/b522/mcp.test
/tmp/go-build1985989918/b522/mcp.test
-test.testlogfile=/tmp/go-build1985989918/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s /tmp�� /run/containerd/-p
herFiles,CFiles,main by/31b594e5b708d-lang=go1.25 ntime.v2.task/mogit
-guard/target/deshow
-guard/target/de7291de63ecded2ae0119c7bba93a1d428d68106a:internal/server/routed_test.go
296/log.json b2f7�� 081a786f99487854go1.25.9 y er-linux
ntime.v2.task/mo/opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/tools/linux64/java/lib/jspawnhelper
/tmp/awmg-log-te21.0.9&#43;10-LTS --routed er-linux` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 24, 2026
…package duplication (#4497)

The `get_collaborator_permission` arg parsing logic
(`owner`/`repo`/`username` extraction + validation) was duplicated
verbatim in `internal/server/unified.go` and `internal/proxy/proxy.go`,
creating a drift risk between two separate HTTP implementations.

## Changes

- **`internal/mcp/collaborator_permission.go`** — new
`ParseCollaboratorPermissionArgs(argsMap map[string]interface{}) (owner,
repo, username string, err error)` helper; returns partial values on
error so callers can include them in log messages
- **`internal/mcp/collaborator_permission_test.go`** —
`TestParseCollaboratorPermissionArgs` covering happy path, each missing
field, and partial-value-on-error behavior
- **`internal/server/unified.go`** — `callCollaboratorPermission`
replaces 8-line inline extraction with the shared helper
- **`internal/proxy/proxy.go`** — `restBackendCaller.CallTool` uses the
helper via function-scoped `collabOwner/collabRepo/collabUsername` vars,
also eliminating the redundant post-switch `argsMap` re-read

```go
// Before (duplicated in both files):
owner, _ := argsMap["owner"].(string)
repo, _ := argsMap["repo"].(string)
username, _ := argsMap["username"].(string)
if owner == "" || repo == "" || username == "" {
    return nil, fmt.Errorf("get_collaborator_permission: missing owner/repo/username")
}

// After:
owner, repo, username, err := mcp.ParseCollaboratorPermissionArgs(argsMap)
if err != nil {
    logUnified.Printf("get_collaborator_permission: missing required args (owner=%q repo=%q username=%q)", owner, repo, username)
    return nil, err
}
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build2075080314/b509/launcher.test
/tmp/go-build2075080314/b509/launcher.test
-test.testlogfile=/tmp/go-build2075080314/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true p/go-build main
x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build1743922486/b513/launcher.test
/tmp/go-build1743922486/b513/launcher.test
-test.testlogfile=/tmp/go-build1743922486/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -o 5080314/b497/difc.test
-trimpath x_amd64/vet -p google.golang.or-atomic -lang=go1.24
x_amd64/vet -o ry=1 -trimpath x_amd64/vet -p
google.golang.or/usr/bin/runc -lang=go1.24 x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2075080314/b491/config.test
/tmp/go-build2075080314/b491/config.test
-test.testlogfile=/tmp/go-build2075080314/b491/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/c-p o
x_amd64/asm` (dns block)
> - Triggering command: `/tmp/go-build1743922486/b495/config.test
/tmp/go-build1743922486/b495/config.test
-test.testlogfile=/tmp/go-build1743922486/b495/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -o zU9f4ahsV -trimpath
ache/go/1.25.9/x64/pkg/tool/linux_amd64/vet -p
go.opentelemetry/tmp/go-build1387771901/b265/vet.cfg -lang=go1.25 ortcfg
-I aw-mcpg/internal/launcher/connection_pool.go
aw-mcpg/internal/launcher/health_monitor.go` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build2075080314/b509/launcher.test
/tmp/go-build2075080314/b509/launcher.test
-test.testlogfile=/tmp/go-build2075080314/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true p/go-build main
x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build1743922486/b513/launcher.test
/tmp/go-build1743922486/b513/launcher.test
-test.testlogfile=/tmp/go-build1743922486/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -o 5080314/b497/difc.test
-trimpath x_amd64/vet -p google.golang.or-atomic -lang=go1.24
x_amd64/vet -o ry=1 -trimpath x_amd64/vet -p
google.golang.or/usr/bin/runc -lang=go1.24 x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build2075080314/b509/launcher.test
/tmp/go-build2075080314/b509/launcher.test
-test.testlogfile=/tmp/go-build2075080314/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true p/go-build main
x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build1743922486/b513/launcher.test
/tmp/go-build1743922486/b513/launcher.test
-test.testlogfile=/tmp/go-build1743922486/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -o 5080314/b497/difc.test
-trimpath x_amd64/vet -p google.golang.or-atomic -lang=go1.24
x_amd64/vet -o ry=1 -trimpath x_amd64/vet -p
google.golang.or/usr/bin/runc -lang=go1.24 x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2075080314/b518/mcp.test
/tmp/go-build2075080314/b518/mcp.test
-test.testlogfile=/tmp/go-build2075080314/b518/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
rnal/pragma/prag-errorsas ache/go/1.25.9/x-ifaceassert
64/pkg/tool/linu-nilfunc -p syscall -lang=go1.25
64/pkg/tool/linu-buildtags go_.�� dns/dns_resolver-errorsas .cfg
x_amd64/compile -p crypto/ed25519 -lang=go1.25 x_amd64/compile` (dns
block)
> - Triggering command: `/tmp/go-build1743922486/b522/mcp.test
/tmp/go-build1743922486/b522/mcp.test
-test.testlogfile=/tmp/go-build1743922486/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -o
/tmp/go-build2075080314/b439/_pkg_.a -trimpath x_amd64/vet -p
google.golang.or--version -lang=go1.25 x_amd64/vet -ato�� submodules |
head -n 10 din}} x_amd64/vet -errorsas -ifaceassert -nilfunc
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3917726863/b253/mcp.test
/tmp/go-build3917726863/b253/mcp.test
-test.testlogfile=/tmp/go-build3917726863/b253/testlog.txt
-test.paniconexit0 -test.timeout=10m0s bug/��
bug/deps/github_guard-57d41235e07a5585.3r7b32ab9hw1mmy6a1aekmmsh.1qicuz7.rcgu.o
bug/deps/github_guard-57d41235e07a5585.485oswk5h4p2kq4dabhq5b2ke.1qicuz7.rcgu.o
-guard/target/de--diagnostic-width=120 by/5614fb8de41e5mktemp -trimpath
lib/rustlib/x86_codeql.XXXXXXXX lib/rustlib/x86_-C lib/��
-guard/target/debug/deps/rustcHdHtL6/symbols.o
-guard/target/debug/deps/github_guard-57d41235e07a5585.0r6f2y9pmz8tylr32cgwnziux.1qicuz7.rcgu.o
-guard/target/debug/deps/github_guard-57d41235e07a5585.0y8i0suihruczucboywd9kbz6.1qicuz7.rcgu.o
-guard/target/de/bin/sh -guard/target/de-c -guard/target/deecho &#34;
release - Trigger the release workflow (usage: make release
patch|minor|major)&#34;
-guard/target/debug/deps/github_guard-57d41235e07a5585.1yg4dgf4ofc88gtczrpthgg1u.1qicuz7.rcgu.o`
(dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 24, 2026
…on (#4498)

The four-step DIFC initialization sequence (`ParseEnforcementMode` →
`NewAgentRegistryWithDefaults` → `NewCapabilities` →
`NewEvaluatorWithMode`) was duplicated verbatim in both
`server/unified.go` and `proxy/proxy.go`, with silently diverging
default modes (`EnforcementStrict` vs `EnforcementFilter`).

## Changes

- **`internal/difc/evaluator.go`** — Adds `DIFCComponents` struct and
`NewComponents(modeStr string, defaultMode EnforcementMode)
DIFCComponents` constructor that encapsulates the full initialization
sequence
- **`internal/server/unified.go`** — Replaces inline DIFC init with
`difc.NewComponents(cfg.DIFCMode, difc.EnforcementStrict)`
- **`internal/proxy/proxy.go`** — Replaces inline DIFC init with
`difc.NewComponents(cfg.DIFCMode, difc.EnforcementFilter)`, preserving
the proxy-specific warning log for invalid mode strings

```go
// internal/difc/evaluator.go
type DIFCComponents struct {
    Mode          EnforcementMode
    AgentRegistry *AgentRegistry
    Capabilities  *Capabilities
    Evaluator     *Evaluator
}

func NewComponents(modeStr string, defaultMode EnforcementMode) DIFCComponents {
    mode, err := ParseEnforcementMode(modeStr)
    if err != nil {
        mode = defaultMode
    }
    return DIFCComponents{
        Mode:          mode,
        AgentRegistry: NewAgentRegistryWithDefaults(nil, nil),
        Capabilities:  NewCapabilities(),
        Evaluator:     NewEvaluatorWithMode(mode),
    }
}
```

Future changes to the DIFC initialization sequence (e.g. adding a new
component) now have a single update point.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build2613986933/b513/launcher.test
/tmp/go-build2613986933/b513/launcher.test
-test.testlogfile=/tmp/go-build2613986933/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2613986933/b435/vet.cfg _.a -I x_amd64/vet --gdwarf-5
balancer/gracefu-atomic -o x_amd64/vet -W cks...&#34; t.go
x_amd64/compile . --gdwarf2 893947/b314/ x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build1963674460/b509/launcher.test
/tmp/go-build1963674460/b509/launcher.test
-test.testlogfile=/tmp/go-build1963674460/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true tHjXILjQ_ -buildtags
/opt/hostedtoolcache/go/1.25.9/xjson -errorsas -ifaceassert -nilfunc
StwtP8fWF_W- logs�� tes.crt aw-mcpg/internal/proxy/graphql_r--log-format
7c330d9c11d84b8d-d -errorsas -ifaceassert -nilfunc
ache/go/1.25.9/x-test.timeout=10m0s` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2613986933/b495/config.test
/tmp/go-build2613986933/b495/config.test
-test.testlogfile=/tmp/go-build2613986933/b495/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2613986933/b368/vet.cfg _.a otection x_amd64/vet --gdwarf-5
credentials -o x_amd64/vet -E w6WVsrdoR -I x_amd64/vet -I .io/auto/sdk
-imultiarch x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build1963674460/b491/config.test
/tmp/go-build1963674460/b491/config.test
-test.testlogfile=/tmp/go-build1963674460/b491/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
-unreachable=fal--log-format /tmp/go-build261json docker-buildx
f19db7ad4b9e741c980b3140ec557422c5d/log.json nwind-tables p/bin/as
docker-buildx -ato�� 40a26d5ba8f85386 -buildtags ine
by/6e9cb3f11e119/usr/lib/open-iscsi/net-interface-handler -ifaceassert
-nilfunc ine` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build2613986933/b513/launcher.test
/tmp/go-build2613986933/b513/launcher.test
-test.testlogfile=/tmp/go-build2613986933/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2613986933/b435/vet.cfg _.a -I x_amd64/vet --gdwarf-5
balancer/gracefu-atomic -o x_amd64/vet -W cks...&#34; t.go
x_amd64/compile . --gdwarf2 893947/b314/ x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build1963674460/b509/launcher.test
/tmp/go-build1963674460/b509/launcher.test
-test.testlogfile=/tmp/go-build1963674460/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true tHjXILjQ_ -buildtags
/opt/hostedtoolcache/go/1.25.9/xjson -errorsas -ifaceassert -nilfunc
StwtP8fWF_W- logs�� tes.crt aw-mcpg/internal/proxy/graphql_r--log-format
7c330d9c11d84b8d-d -errorsas -ifaceassert -nilfunc
ache/go/1.25.9/x-test.timeout=10m0s` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build2613986933/b513/launcher.test
/tmp/go-build2613986933/b513/launcher.test
-test.testlogfile=/tmp/go-build2613986933/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2613986933/b435/vet.cfg _.a -I x_amd64/vet --gdwarf-5
balancer/gracefu-atomic -o x_amd64/vet -W cks...&#34; t.go
x_amd64/compile . --gdwarf2 893947/b314/ x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build1963674460/b509/launcher.test
/tmp/go-build1963674460/b509/launcher.test
-test.testlogfile=/tmp/go-build1963674460/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true tHjXILjQ_ -buildtags
/opt/hostedtoolcache/go/1.25.9/xjson -errorsas -ifaceassert -nilfunc
StwtP8fWF_W- logs�� tes.crt aw-mcpg/internal/proxy/graphql_r--log-format
7c330d9c11d84b8d-d -errorsas -ifaceassert -nilfunc
ache/go/1.25.9/x-test.timeout=10m0s` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2613986933/b522/mcp.test
/tmp/go-build2613986933/b522/mcp.test
-test.testlogfile=/tmp/go-build2613986933/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s 8939�� cfg
elemetry.io/otel-ifaceassert x_amd64/vet --gdwarf-5
telabs/wazero/in/usr/bin/runc -o x_amd64/vet cfg 893947/b432/_pkg_.a
-trimpath x_amd64/vet -p /internal/httpco/usr/bin/runc -lang=go1.17
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build1963674460/b518/mcp.test
/tmp/go-build1963674460/b518/mcp.test
-test.testlogfile=/tmp/go-build1963674460/b518/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true y -buildtags` (dns
block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 24, 2026
…nctions (8 findings) (#4516)

Automated semantic analysis identified 8 actionable code organization
issues across `internal/`. This PR resolves all of them.

## P1 — Quick Wins

- **Remove duplicate JSON-RPC types** (`server/sdk_logging.go`):
`JSONRPCRequest`, `JSONRPCResponse`, `JSONRPCError` were structurally
identical to `mcp.Request`, `mcp.Response`, `mcp.ResponseError`.
Replaced with the canonical `mcp` types and merged `sdk_logging.go` into
`http_helpers.go` (now a single-function file after the type removal).

- **Relocate `isEffectivelyEmpty`** (`logger/rpc_helpers.go` →
`logger/rpc_formatter.go`): Function had one caller in
`rpc_formatter.go`; moved to co-locate it.

- **Consistent duration formatting** (`server/circuit_breaker.go`):
`formatResetAt` used raw `time.Duration.String()`; replaced with
`strutil.FormatDuration` to match the rest of the codebase.

- **Fix stdlib `log` leakage** (`proxy/proxy.go`): Two `log.Printf`
calls bypassed the project's structured `logProxy` logger and
`DEBUG=proxy:*` filtering. Replaced and removed the `"log"` import.

## P2 — Medium Effort

- **Relocate Docker helpers** (`config/docker_helpers.go` →
`sys/docker.go`): Six runtime Docker inspection functions
(`CheckDockerAccessible`, `ValidateContainerID`, `CheckPortMapping`,
`CheckStdinInteractive`, `CheckLogDirMounted`, `runDockerInspect`)
belonged in `internal/sys` alongside container detection, not in the
config parser. Exported the functions, updated callers in
`config/validation_env.go`, and migrated tests to `sys/docker_test.go`.

- **Promote `sessionSuffix` to `strutil`**: `launcher/log_helpers.go`
defined a private `sessionSuffix` helper; `mcp/errors.go` inlined the
same logic. Extracted as `strutil.SessionSuffix` and updated both
callers.

- **Deduplicate OTel HTTP wrapping** (`server.WithOTELTracing`): ~80% of
its implementation duplicated `tracing.WrapHTTPHandler`. Refactored to
delegate W3C extraction and span creation to `WrapHTTPHandler`, with a
post-handler closure that enriches the span with session ID:

```go
func WithOTELTracing(next http.Handler, tag string) http.Handler {
    enriched := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        next.ServeHTTP(w, r)
        // r.Context() reflects session ID after setupSessionCallback mutates *r in-place
        span := oteltrace.SpanFromContext(r.Context())
        span.SetAttributes(attribute.String("session.id", auth.TruncateSessionID(SessionIDFromContext(r.Context()))))
    })
    return tracing.WrapHTTPHandler(enriched, "gateway.request", attribute.String("gateway.tag", tag))
}
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build227273503/b509/launcher.test
/tmp/go-build227273503/b509/launcher.test
-test.testlogfile=/tmp/go-build227273503/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ect/protoreflect/methods.go ect/protoreflect/proto.go x_amd64/compile`
(dns block)
> - Triggering command: `/tmp/go-build2433055712/b491/launcher.test
/tmp/go-build2433055712/b491/launcher.test
-test.testlogfile=/tmp/go-build2433055712/b491/testlog.txt
-test.paniconexit0 -test.timeout=10m0s ortc�� g_.a
64/src/net/http/internal/httpcom-ifaceassert x_amd64/vet --gdwarf-5 ls
-o x_amd64/vet -W -L1q213H7 /tmp/go-build2392850310/b151/ x_amd64/vet .
telabs/wazero/indocker-cli-plugin-metadata --64 x_amd64/vet` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2433055712/b224/config.test
/tmp/go-build2433055712/b224/config.test
-test.testlogfile=/tmp/go-build2433055712/b224/testlog.txt
-test.paniconexit0 -test.timeout=10m0s ortc�� /tmp/go-build239-errorsas
64/src/vendor/go-ifaceassert x_amd64/vet -p crypto/internal/-o
-lang=go1.25 x_amd64/vet 2850�� 1.80.0/internal/-p -I x_amd64/vet
64/src/os/user/gsleep --64 -o x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build1042049869/b491/config.test
/tmp/go-build1042049869/b491/config.test
-test.testlogfile=/tmp/go-build1042049869/b491/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
-guard/target/de--irreversible-delete -guard/target/de-U0
-guard/target/de449d321381cc393f6a76bce0f87da0469da1f43b
-guard/target/degit -guard/target/deshow
-guard/target/de449d321381cc393f6a76bce0f87da0469da1f43b:internal/server/http_helpers.go
-guard/target/debug/deps/github_guard-57d41235e07a5585.1yg4dgf4ofc88gtczrpthgg1u.035gz5i.rcgu.o
-gua�� elpers.go
-guard/target/debug/deps/github_guard-57d41235e07a5585.2z8afzdm9zucrirrh7hnf4z1l.035gz5i.rcgu.o
-guard/target/debug/deps/github_guard-57d41235e07a5585.34w8f3apoo4qlefxtp7qruodt.035gz5i.rcgu.o
-guard/target/de/bin/sh -guard/target/de-c -guard/target/deecho &#34;
test-rust - Run Rust guard unit tests (requires cargo)&#34;
-guard/target/debug/deps/github_guard-57d41235e07a5585.3o0f2kbgbq7jvxzdnkys32nfz.035gz5i.rcgu.o`
(dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build227273503/b509/launcher.test
/tmp/go-build227273503/b509/launcher.test
-test.testlogfile=/tmp/go-build227273503/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ect/protoreflect/methods.go ect/protoreflect/proto.go x_amd64/compile`
(dns block)
> - Triggering command: `/tmp/go-build2433055712/b491/launcher.test
/tmp/go-build2433055712/b491/launcher.test
-test.testlogfile=/tmp/go-build2433055712/b491/testlog.txt
-test.paniconexit0 -test.timeout=10m0s ortc�� g_.a
64/src/net/http/internal/httpcom-ifaceassert x_amd64/vet --gdwarf-5 ls
-o x_amd64/vet -W -L1q213H7 /tmp/go-build2392850310/b151/ x_amd64/vet .
telabs/wazero/indocker-cli-plugin-metadata --64 x_amd64/vet` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build227273503/b509/launcher.test
/tmp/go-build227273503/b509/launcher.test
-test.testlogfile=/tmp/go-build227273503/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
ect/protoreflect/methods.go ect/protoreflect/proto.go x_amd64/compile`
(dns block)
> - Triggering command: `/tmp/go-build2433055712/b491/launcher.test
/tmp/go-build2433055712/b491/launcher.test
-test.testlogfile=/tmp/go-build2433055712/b491/testlog.txt
-test.paniconexit0 -test.timeout=10m0s ortc�� g_.a
64/src/net/http/internal/httpcom-ifaceassert x_amd64/vet --gdwarf-5 ls
-o x_amd64/vet -W -L1q213H7 /tmp/go-build2392850310/b151/ x_amd64/vet .
telabs/wazero/indocker-cli-plugin-metadata --64 x_amd64/vet` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build227273503/b518/mcp.test
/tmp/go-build227273503/b518/mcp.test
-test.testlogfile=/tmp/go-build227273503/b518/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
rnal/filedesc/build.go rnal/filedesc/desc.go x_amd64/compile -nxv
2850310/b130/ 64/bin/git x_amd64/compile go_.��
h/v2@v2.3.0/xxha-errorsas ache/go/1.25.9/x-ifaceassert` (dns block)
> - Triggering command: `/tmp/go-build2433055712/b494/mcp.test
/tmp/go-build2433055712/b494/mcp.test
-test.testlogfile=/tmp/go-build2433055712/b494/testlog.txt
-test.paniconexit0 -test.timeout=10m0s 2850�� g_.a
om/tetratelabs/wazero@v1.11.0/in-ifaceassert x_amd64/vet --gdwarf-5 --64
-o x_amd64/vet -W 2850310/b246/_pkg_.a 5oDDV1CJn x_amd64/vet .
telabs/wazero/in/usr/bin/runc --64 x_amd64/vet` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 28, 2026
… HTTP error helpers (#4740)

Three structural duplication patterns across the MCP gateway server and
proxy — a shared LabelAgent initialization sequence reimplemented in two
places, identical DIFC component field sets in two structs, and an
inconsistent HTTP error response shape in the proxy.

## Pattern 1 — `guard.RunLabelAgent` shared helper
(`internal/guard/init.go`)

Both `server/guard_init.go` (`ensureGuardInitialized`) and
`proxy/proxy.go` (`initGuardPolicy`) independently implemented the same
4-step pipeline. Extracted into a single shared function:

```go
// RunLabelAgent: payload → LabelAgent → nil-check → ApplyLabelAgentResult → (mode, result, error)
mode, result, err := guard.RunLabelAgent(ctx, g, payload, backend, caps, agentLabels, defaultMode)
```

Bug fixes and behaviour changes now have a single source of truth.

## Pattern 2 — Embed `difc.DIFCComponents` in both structs

`UnifiedServer` and proxy `Server` each declared the same trio of fields
(`agentRegistry`, `capabilities`, `evaluator`), plus `enforcementMode`
in the proxy. Both now embed `difc.DIFCComponents` — the struct already
returned by `difc.NewComponents()`:

```go
// Before: 3–4 individual fields initialized from difcComponents.Foo
// After:
type Server struct {
    guard guard.Guard
    difc.DIFCComponents   // promotes AgentRegistry, Capabilities, Evaluator, Mode
    ...
}
s := &Server{guard: g, DIFCComponents: difcComponents, ...}
```

Adding a new DIFC component now requires a single change to
`DIFCComponents`/`NewComponents`.

## Pattern 3 — `httputil.WriteErrorResponse` shared helper

Added `httputil.WriteErrorResponse(w, statusCode, code, message)` so
both packages share a single error formatter. This also fixes a
pre-existing inconsistency: proxy DIFC 403s previously emitted
`{"message": "..."}` while every other gateway error used `{"error":
..., "message": ...}`. `writeDIFCForbidden` now emits `{"error":
"difc_forbidden", "message": "..."}`.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build285171061/b509/launcher.test
/tmp/go-build285171061/b509/launcher.test
-test.testlogfile=/tmp/go-build285171061/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true x86.go cfg
x_amd64/compile OUTPUT 171061/b106/syma-atomic 168.63.129.16
x_amd64/compile -o 171061/b205/_pkg-errorsas cfg
ache/Python/3.12-nilfunc -p /unix -lang=go1.25
/opt/hostedtoolc-buildtags` (dns block)
> - Triggering command: `/tmp/go-build1554483255/b513/launcher.test
/tmp/go-build1554483255/b513/launcher.test
-test.testlogfile=/tmp/go-build1554483255/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s .cfg��
pzBVcSErY9tCHTz_H-AO/pzBVcSErY9tCHTz_H-AO -goversion
64/pkg/tool/linux_amd64/vet -c=4 -nolocalimports -importcfg
64/pkg/tool/linux_amd64/vet .cfg�� origin REDACTED .13/x64/bash _.a
171061/b168/ x_amd64/vet ache/go/1.25.9/x64/pkg/tool/linux_amd64/vet`
(dns block)
> - `https://api.github.com/graphql`
> - Triggering command: `/usr/bin/gh gh issue close 4711 --comment
Resolved by PR #4740 which addresses all three duplicate code patterns
identified in this analysis.
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libminiz_oxide-2b6a8d2f6e1dc71b.rlib
ithub-guard/rust-guard/target/debug/build/serde_core-842ae9a69327bc0f/build_script_build-842ae9a69327bc0f.build_-v
c1063f.rlib -S
1f1acc601a04e465289083e76e0e9d1168034a3b0a40563a2ef2e757:internal/server/label_agent_test.go
known-linux-gnu/lib/rustlib/x86_--others know��` (http block)
> - Triggering command: `/usr/bin/gh gh auth status
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.11.rcgu.o
-gua�� til.go
-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.14.rcgu-c
c1063f.rlib ithub-guard/rustgit erd
ache/go/1.25.9/x289083e76e0e9d1168034a3b0a40563a2ef2e757:internal/server/unified.go
known-linux-gnu/lib/rustlib/x86_-dynamic-linker g/gh��
ckend_tool_difc_test.go known-linux-gnu/lib/rustlib/x86_-z
ithub-guard/rust-guard/target/debug/deps/rustchEkyPI/symbols.o
ithub-guard/rustgit ithub-guard/rust-c
ithub-guard/rustlog.showsignature=false ithub-guard/rustlog` (http
block)
> - `https://api.github.com/repos/github/gh-aw-mcpg/issues/4711`
> - Triggering command: `/usr/bin/curl curl -s -X PATCH -H Accept:
application/vnd.github&#43;json -H Authorization: ****** -H
X-GitHub-Api-Version: 2022-11-28 REDACTED -d
{&#34;state&#34;:&#34;closed&#34;}
ithub-guard/rust-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da/opt/google/chrome/chrome_crashpad_handler
ithub-guard/rust-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da--monitor-self
ithub-guard/rust-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da--monitor-self-annotation=ptype=crashpad-handler
ithub-guard/rust/opt/google/chrome/chrome
ithub-guard/rust--disable-field-trial-config
ithub-guard/rust--disable-REDACTED-networking
ithub-guard/rust--disable-REDACTED-timer-throttling` (http block)
> - Triggering command: `/usr/bin/curl curl -s -X PATCH -H Accept:
application/vnd.github&#43;json -H Authorization: ****** -H
X-GitHub-Api-Version: 2022-11-28 REDACTED -d
{&#34;state&#34;:&#34;closed&#34;} encies&#34;
ithub-guard/rust-guard/target/debug/deps/github_guard-57d41235e07a5585.2z8afzdm9zucrirrh7hnf4z1l--norc
ithub-guard/rust-guard/target/debug/deps/github_guard-57d41235e07a5585.34w8f3apoo4qlefxtp7qruodt--noprofile
ithub-guard/rustbash ithub-guard/rust--norc ithub-guard/rust--noprofile
ithub-guard/rust-guard/target/debug/deps/github_guard-57d41235e07a5585.3o0f2kbgbq7jvxzdnkys32nfz.155o5i1.rcgu.o`
(http block)
> - Triggering command: `/usr/bin/curl curl -s -X PATCH -H Accept:
application/vnd.github&#43;json -H Authorization: ****** -H
X-GitHub-Api-Version: 2022-11-28 REDACTED -d
{&#34;state&#34;:&#34;closed&#34;} 9c0cb1c7158.rlib--annotation=channel=
.rlib 6b2b26a06.rlib 327.rlib 653.rlib 86b29d.rlib bd.rlib` (http block)
> - `https://api.github.com/repos/github/gh-aw-mcpg/issues/4712`
> - Triggering command: `/usr/bin/curl curl -s -X PATCH -H Accept:
application/vnd.github&#43;json -H Authorization: ****** -H
X-GitHub-Api-Version: 2022-11-28 REDACTED -d
{&#34;state&#34;:&#34;closed&#34;}
ithub-guard/rust-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da/opt/google/chrome/chrome
ithub-guard/rust-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da--disable-field-trial-config
ithub-guard/rust-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da--disable-REDACTED-networking
ithub-guard/rust/opt/google/chrome/chrome_crashpad_handler
ithub-guard/rust--no-periodic-tasks
ithub-guard/rust--monitor-self-annotation=ptype=crashpad-handler
ithub-guard/rust--database=/root/.config/google-chrome/Crash Reports`
(http block)
> - Triggering command: `/usr/bin/curl curl -s -X PATCH -H Accept:
application/vnd.github&#43;json -H Authorization: ****** -H
X-GitHub-Api-Version: 2022-11-28 REDACTED -d
{&#34;state&#34;:&#34;closed&#34;} (for agents before completion)&#34;
ithub-guard/rust-guard/target/debug/deps/github_guard-57d41235e07a5585.2z8afzdm9zucrirrh7hnf4z1l--norc
ithub-guard/rust-guard/target/debug/deps/github_guard-57d41235e07a5585.34w8f3apoo4qlefxtp7qruodt--noprofile
ithub-guard/rustbash ithub-guard/rust--norc ithub-guard/rust--noprofile
ithub-guard/rust-guard/target/debug/deps/github_guard-57d41235e07a5585.3o0f2kbgbq7jvxzdnkys32nfz.155o5i1.rcgu.o`
(http block)
> - `https://api.github.com/repos/github/gh-aw-mcpg/issues/4713`
> - Triggering command: `/usr/bin/curl curl -s -X PATCH -H Accept:
application/vnd.github&#43;json -H Authorization: ****** -H
X-GitHub-Api-Version: 2022-11-28 REDACTED -d
{&#34;state&#34;:&#34;closed&#34;}
ithub-guard/rustcom.semmle.cli2.CodeQL ithub-guard/rustenv_argv
ithub-guard/rustdataset
ithub-guard/rust/opt/google/chrome/chrome_crashpad_handler
ithub-guard/rust--monitor-self
ithub-guard/rust--monitor-self-annotation=ptype=crashpad-handler
ithub-guard/rust--database=/root/.config/google-chrome/Crash Reports`
(http block)
> - Triggering command: `/usr/bin/curl curl -s -X PATCH -H Accept:
application/vnd.github&#43;json -H Authorization: ****** -H
X-GitHub-Api-Version: 2022-11-28 REDACTED -d
{&#34;state&#34;:&#34;closed&#34;} .rlib 6b2b26a06.rlib 327.rlib
653.rlib 86b29d.rlib bd.rlib ad3.rlib` (http block)
> - `https://api.github.com/repos/github/gh-aw-mcpg/issues/4714`
> - Triggering command: `/usr/bin/curl curl -s -X PATCH -H Accept:
application/vnd.github&#43;json -H Authorization: ****** -H
X-GitHub-Api-Version: 2022-11-28 REDACTED -d
{&#34;state&#34;:&#34;closed&#34;} known-linux-gnu/--format
known-linux-gnu/sarifv2.1.0 /usr/lib/network--output
ofileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRo--database=/root/.config/google-chrome/Crash
Reports --log-format ithub-guard/rust--disable-REDACTED-networking
-linux-gnu/crti.--disable-REDACTED-timer-throttling` (http block)
> - Triggering command: `/usr/bin/curl curl -s -X PATCH -H Accept:
application/vnd.github&#43;json -H Authorization: ****** -H
X-GitHub-Api-Version: 2022-11-28 REDACTED -d
{&#34;state&#34;:&#34;closed&#34;} .rlib 6b2b26a06.rlib 327.rlib
653.rlib 86b29d.rlib bd.rlib ad3.rlib` (http block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build285171061/b491/config.test
/tmp/go-build285171061/b491/config.test
-test.testlogfile=/tmp/go-build285171061/b491/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/c-p
ttp/httpguts/gutgoogle.golang.org/grpc/credentials x_amd64/compile` (dns
block)
> - Triggering command: `/tmp/go-build1554483255/b495/config.test
/tmp/go-build1554483255/b495/config.test
-test.testlogfile=/tmp/go-build1554483255/b495/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2193852037/b481/_pkg_.a --version
171061/b172/_x00-buildtags 64/pkg/tool/linux_amd64/vet 64/src/net
-trimpath 171061/b172/ 64/pkg/tool/linux_amd64/vet -o .cfg -trimpath
x_amd64/asm -p github.com/githu-o -lang=go1.25 x_amd64/asm` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build285171061/b509/launcher.test
/tmp/go-build285171061/b509/launcher.test
-test.testlogfile=/tmp/go-build285171061/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true x86.go cfg
x_amd64/compile OUTPUT 171061/b106/syma-atomic 168.63.129.16
x_amd64/compile -o 171061/b205/_pkg-errorsas cfg
ache/Python/3.12-nilfunc -p /unix -lang=go1.25
/opt/hostedtoolc-buildtags` (dns block)
> - Triggering command: `/tmp/go-build1554483255/b513/launcher.test
/tmp/go-build1554483255/b513/launcher.test
-test.testlogfile=/tmp/go-build1554483255/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s .cfg��
pzBVcSErY9tCHTz_H-AO/pzBVcSErY9tCHTz_H-AO -goversion
64/pkg/tool/linux_amd64/vet -c=4 -nolocalimports -importcfg
64/pkg/tool/linux_amd64/vet .cfg�� origin REDACTED .13/x64/bash _.a
171061/b168/ x_amd64/vet ache/go/1.25.9/x64/pkg/tool/linux_amd64/vet`
(dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build285171061/b509/launcher.test
/tmp/go-build285171061/b509/launcher.test
-test.testlogfile=/tmp/go-build285171061/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true x86.go cfg
x_amd64/compile OUTPUT 171061/b106/syma-atomic 168.63.129.16
x_amd64/compile -o 171061/b205/_pkg-errorsas cfg
ache/Python/3.12-nilfunc -p /unix -lang=go1.25
/opt/hostedtoolc-buildtags` (dns block)
> - Triggering command: `/tmp/go-build1554483255/b513/launcher.test
/tmp/go-build1554483255/b513/launcher.test
-test.testlogfile=/tmp/go-build1554483255/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s .cfg��
pzBVcSErY9tCHTz_H-AO/pzBVcSErY9tCHTz_H-AO -goversion
64/pkg/tool/linux_amd64/vet -c=4 -nolocalimports -importcfg
64/pkg/tool/linux_amd64/vet .cfg�� origin REDACTED .13/x64/bash _.a
171061/b168/ x_amd64/vet ache/go/1.25.9/x64/pkg/tool/linux_amd64/vet`
(dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build285171061/b518/mcp.test
/tmp/go-build285171061/b518/mcp.test
-test.testlogfile=/tmp/go-build285171061/b518/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
pickfirst/intern-errorsas 171061/b027/vet.-ifaceassert x_amd64/compile
-p crypto/internal//usr/bin/runc -lang=go1.25 x_amd64/compile -I
@v1.43.0/attribute/internal/xxhash/xxhash.go cfg x_amd64/vet --gdwarf-5
--64 -o x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build1554483255/b522/mcp.test
/tmp/go-build1554483255/b522/mcp.test
-test.testlogfile=/tmp/go-build1554483255/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s push�� .cfg origin
64/pkg/tool/linux_amd64/vet _.a 171061/b168/ x_amd64/vet
64/pkg/tool/linux_amd64/vet .cfg�� 5395607/b106/vet.cfg x_amd64/vet
docker-compose uf@v1.36.11/inte/usr/libexec/docker/docker-init -I
x_amd64/compile docker-compose` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request Apr 28, 2026
…lementation (#4750)

The `itchyny/gojq` module review identified three actionable
improvements to `internal/middleware/jqschema.go`: replace the pure-jq
recursive schema walk with a native Go function, harden the type switch
against `json.Number`/`nil` inputs, and clarify benchmark intent.

## Native Go `walk_schema` via `gojq.WithFunction`

Adds `inferSchema(v interface{}) interface{}` — a pure-Go recursive
schema walker — and registers it as a native gojq function. The jq
filter collapses from 12 lines of recursive jq bytecode to a single
call:

```go
// Before: 12-line recursive jq def
const jqSchemaFilter = `
def walk_schema:
  . as $in |
  if type == "object" then
    reduce keys[] as $k ({}; . + {($k): ($in[$k] | walk_schema)})
  ...
walk_schema
`

// After: native Go function, trivial jq entry point
const jqSchemaFilter = `walk_schema`

// Registered at compile time:
gojq.Compile(query,
    gojq.WithFunction("walk_schema", 0, 0, func(v interface{}, _ []interface{}) interface{} {
        return inferSchema(v)
    }),
)
```

`inferSchema` handles all jq type names (`"null"`, `"boolean"`,
`"number"`, `"string"`) and preserves the array-collapsing behaviour
(first element only, `[]` for empty).

## Defensive type switch in `WrapToolHandler`

Adds `case nil` (early return, nil schema) and `case json.Number`
(convert via `.Float64()`) to the type switch that decides whether to
skip the `json.Unmarshal` round-trip. Guards against decoders using
`UseNumber()`.

## Tests

- `TestInferSchema` — exhaustive unit tests for every type case of
`inferSchema`
- `TestInferSchema_MatchesJqOutput` — cross-checks native Go output
against `applyJqSchema` to prevent drift
- `TestWrapToolHandler_JsonNumberData` — end-to-end coverage of the new
`json.Number` path

## Benchmark clarification

Adds an explicit comment to `BenchmarkApplyJqSchema_ParseEveryTime`
noting it intentionally simulates the degraded parse-every-call path for
comparison purposes only.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build2697671537/b513/launcher.test
/tmp/go-build2697671537/b513/launcher.test
-test.testlogfile=/tmp/go-build2697671537/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2697671537/b410/vet.cfg se 690953/b038/vet.cfg x_amd64/vet
. pb` (dns block)
> - Triggering command: `/tmp/go-build2068934155/b509/launcher.test
/tmp/go-build2068934155/b509/launcher.test
-test.testlogfile=/tmp/go-build2068934155/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 83096d3e13560ff0
64/pkg/tool/linu/opt/hostedtoolcjson 7671537/b486/vet.cfg OuzHqgGgH cfg
64/pkg/tool/linu--log
/opt/hostedtoolc/var/lib/docker/buildkit/executor/runc-log.json -ato��
-bool ettings.Ports}} 3874a3be3dd1a781b6hh82lckewk8vbuoyc6zqssf
-errorsas -ifaceassert -nilfunc ache/go/1.25.9/x-buildtags` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2697671537/b495/config.test
/tmp/go-build2697671537/b495/config.test
-test.testlogfile=/tmp/go-build2697671537/b495/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2697671537/b395/vet.cfg se t.go x_amd64/compile . --gdwarf2
--64 x_amd64/compile` (dns block)
> - Triggering command: `/tmp/go-build2068934155/b491/config.test
/tmp/go-build2068934155/b491/config.test
-test.testlogfile=/tmp/go-build2068934155/b491/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
5272951ab22a7972c140e0b7a44abee6634cf399ad4a01e54bb x_amd64/compile
ateway_with_pipe.sh` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build2697671537/b513/launcher.test
/tmp/go-build2697671537/b513/launcher.test
-test.testlogfile=/tmp/go-build2697671537/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2697671537/b410/vet.cfg se 690953/b038/vet.cfg x_amd64/vet
. pb` (dns block)
> - Triggering command: `/tmp/go-build2068934155/b509/launcher.test
/tmp/go-build2068934155/b509/launcher.test
-test.testlogfile=/tmp/go-build2068934155/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 83096d3e13560ff0
64/pkg/tool/linu/opt/hostedtoolcjson 7671537/b486/vet.cfg OuzHqgGgH cfg
64/pkg/tool/linu--log
/opt/hostedtoolc/var/lib/docker/buildkit/executor/runc-log.json -ato��
-bool ettings.Ports}} 3874a3be3dd1a781b6hh82lckewk8vbuoyc6zqssf
-errorsas -ifaceassert -nilfunc ache/go/1.25.9/x-buildtags` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build2697671537/b513/launcher.test
/tmp/go-build2697671537/b513/launcher.test
-test.testlogfile=/tmp/go-build2697671537/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build2697671537/b410/vet.cfg se 690953/b038/vet.cfg x_amd64/vet
. pb` (dns block)
> - Triggering command: `/tmp/go-build2068934155/b509/launcher.test
/tmp/go-build2068934155/b509/launcher.test
-test.testlogfile=/tmp/go-build2068934155/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 83096d3e13560ff0
64/pkg/tool/linu/opt/hostedtoolcjson 7671537/b486/vet.cfg OuzHqgGgH cfg
64/pkg/tool/linu--log
/opt/hostedtoolc/var/lib/docker/buildkit/executor/runc-log.json -ato��
-bool ettings.Ports}} 3874a3be3dd1a781b6hh82lckewk8vbuoyc6zqssf
-errorsas -ifaceassert -nilfunc ache/go/1.25.9/x-buildtags` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build2697671537/b522/mcp.test
/tmp/go-build2697671537/b522/mcp.test
-test.testlogfile=/tmp/go-build2697671537/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -o g_.a
elemetry.io/otel-ifaceassert x_amd64/vet -p
net/http/interna/usr/bin/runc -lang=go1.25 x_amd64/vet -uns�� .cfg
elemetry.io/otel@v1.43.0/propagation/doc.go x_amd64/vet go1.25.9
.io/otel/baggage/usr/bin/runc -nolocalimports x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build2068934155/b518/mcp.test
/tmp/go-build2068934155/b518/mcp.test
-test.testlogfile=/tmp/go-build2068934155/b518/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 93bff293c3594aa8
-buildtags .d/chrony-onoffline by/edae42a48ad93bash -ifaceassert
-nilfunc .d/chrony-onoffline -tes�� cf399ad4a01e54bb -test.timeout=10m0s
&#34;CURL_CA_BUNDLE=/-id by/17dafc0aef64ebash t.go x_amd64/compile
152/log.json` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request May 2, 2026
Four findings from semantic function clustering analysis: session
lifecycle helpers in the wrong file, feature-specific constructors
buried in `unified.go`, a zero-logic passthrough wrapper, and two tiny
tracing files that should be one.

## Changes

- **Finding 1 — Session helpers → `session.go`**  
Moved `extractAndValidateSession`, `injectSessionContext`,
`setupSessionCallback`, `logHTTPRequestBody` out of `http_helpers.go`
into `session.go`. `http_helpers.go` shrinks ~100 lines; all session
lifecycle logic is now in one file.

- **Finding 2 — Feature constructors → their owning files**  
  - `buildCircuitBreakers`: `unified.go` → `circuit_breaker.go`  
- `buildAllowedToolSets` + `hasWildcard`: `unified.go` →
`tool_registry.go`
  Added `config` import to both destination files.

- **Finding 3 — Remove `writeErrorResponse` wrapper**  
Deleted the one-line passthrough and replaced all call sites with
`httputil.WriteErrorResponse` directly:
  ```go
  // before
func writeErrorResponse(w http.ResponseWriter, statusCode int, code,
message string) {
      httputil.WriteErrorResponse(w, statusCode, code, message)
  }

  // after — call sites use httputil directly
  httputil.WriteErrorResponse(w, status, code, msg)
  ```

- **Finding 4 — Merge tracing CLI files**  
`cmd/tracing_helpers.go` + `cmd/flags_tracing.go` (75 lines combined) →
`cmd/tracing.go`.

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build3872797525/b513/launcher.test
/tmp/go-build3872797525/b513/launcher.test
-test.testlogfile=/tmp/go-build3872797525/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s 8043��
olang.org/grpc@v1.80.0/internal/idle/idle.go cfg x_amd64/vet . --gdwarf2
--64 x_amd64/vet -I 8043057/b418/_pkg_.a -I x_amd64/vet --gdwarf-5
g/grpc/internal//usr/bin/runc -o x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3399420040/b509/launcher.test
/tmp/go-build3399420040/b509/launcher.test
-test.testlogfile=/tmp/go-build3399420040/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
/tmp/go-build2509960937/b173/vet/run/containerd/io.containerd.runtime.v2.task/moby/db2aa2a60d29ftail
64/pkg/tool/linu-buildtags bash g_.a -trimpath &#34;REQUESTS_CA_B--root
/opt/hostedtoolc/var/run/docker/runtime-runc/moby -uns�� y x_amd64/vet
e-handler @v1.43.0/propaga/usr/libexec/docker/cli-plugins/docker-compose
@v1.43.0/propagadocker-cli-plugin-metadata x_amd64/vet e-handler` (dns
block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3872797525/b495/config.test
/tmp/go-build3872797525/b495/config.test
-test.testlogfile=/tmp/go-build3872797525/b495/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -I g_.a NbAn/6jVna5QQyS18CrolNbAn
x_amd64/vet --gdwarf-5
resolver/delegat/tmp/go-build2509960937/b300/vet.cfg -o x_amd64/vet
8043�� qzhGZjM5u cfg 64/pkg/tool/linux_amd64/vet (compatibility issue
with Go 1.25.0). Continuing with other checks...&#34;; \
elif command -v golan -imultiarch` (dns block)
> - Triggering command: `/tmp/go-build3399420040/b491/config.test
/tmp/go-build3399420040/b491/config.test
-test.testlogfile=/tmp/go-build3399420040/b491/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
88635552ec0a846ca0962f57bea95f938934c2423396c1fa129 x_amd64/compile
ateway_with_pipe.sh cdc8770c07c851b4aae2b041e8136bb0e9e/log.json
pc_health_v1/hea--prefix=/net/ipv4/conf/vethe00a9b0 x_amd64/compile
ateway_with_pipe--prefix=/net/ipv6/conf/vethe00a9b0 -uns��
3c2c91bb777a34fa x_amd64/compile
by/db2aa2a60d29f83ac692768d36051d3e54950f8b5453b528136881dc8dce1cff/log.json
g_.a -trimpath x_amd64/vet
dCQFD9yY_0oeD/ar--prefix=/net/ipv6/conf/vethdaded9f` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build3872797525/b513/launcher.test
/tmp/go-build3872797525/b513/launcher.test
-test.testlogfile=/tmp/go-build3872797525/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s 8043��
olang.org/grpc@v1.80.0/internal/idle/idle.go cfg x_amd64/vet . --gdwarf2
--64 x_amd64/vet -I 8043057/b418/_pkg_.a -I x_amd64/vet --gdwarf-5
g/grpc/internal//usr/bin/runc -o x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3399420040/b509/launcher.test
/tmp/go-build3399420040/b509/launcher.test
-test.testlogfile=/tmp/go-build3399420040/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
/tmp/go-build2509960937/b173/vet/run/containerd/io.containerd.runtime.v2.task/moby/db2aa2a60d29ftail
64/pkg/tool/linu-buildtags bash g_.a -trimpath &#34;REQUESTS_CA_B--root
/opt/hostedtoolc/var/run/docker/runtime-runc/moby -uns�� y x_amd64/vet
e-handler @v1.43.0/propaga/usr/libexec/docker/cli-plugins/docker-compose
@v1.43.0/propagadocker-cli-plugin-metadata x_amd64/vet e-handler` (dns
block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build3872797525/b513/launcher.test
/tmp/go-build3872797525/b513/launcher.test
-test.testlogfile=/tmp/go-build3872797525/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s 8043��
olang.org/grpc@v1.80.0/internal/idle/idle.go cfg x_amd64/vet . --gdwarf2
--64 x_amd64/vet -I 8043057/b418/_pkg_.a -I x_amd64/vet --gdwarf-5
g/grpc/internal//usr/bin/runc -o x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3399420040/b509/launcher.test
/tmp/go-build3399420040/b509/launcher.test
-test.testlogfile=/tmp/go-build3399420040/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
/tmp/go-build2509960937/b173/vet/run/containerd/io.containerd.runtime.v2.task/moby/db2aa2a60d29ftail
64/pkg/tool/linu-buildtags bash g_.a -trimpath &#34;REQUESTS_CA_B--root
/opt/hostedtoolc/var/run/docker/runtime-runc/moby -uns�� y x_amd64/vet
e-handler @v1.43.0/propaga/usr/libexec/docker/cli-plugins/docker-compose
@v1.43.0/propagadocker-cli-plugin-metadata x_amd64/vet e-handler` (dns
block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3872797525/b522/mcp.test
/tmp/go-build3872797525/b522/mcp.test
-test.testlogfile=/tmp/go-build3872797525/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -I 8043057/b414/_pkg_.a -fPIC
x_amd64/vet -pthread g/grpc/internal//usr/bin/runc
-fmessage-length--version x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3399420040/b518/mcp.test
/tmp/go-build3399420040/b518/mcp.test
-test.testlogfile=/tmp/go-build3399420040/b518/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true -I
by/eca09d10600f3--log-format ker/docker-init
by/eca09d10600f3/usr/libexec/docker/cli-plugins/docker-compose
b1a7041eaee94398docker-cli-plugin-metadata x_amd64/vet 91e/log.json
/tmp�� tes.crt x_amd64/vet /usr/sbin/bash by/b7068f2c73a9cbash
/interface.go x_amd64/vet bash` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request May 4, 2026
…` and `first_matching_scope` (#5103)

Two hot-path allocations in the WASM guard's response labeling pipeline:
`extract_mcp_response` unconditionally deep-clones the full JSON payload
on the common (already-unwrapped) path, and `first_matching_scope`
clones a `PolicyScopeEntry` (3× `Option<String>`) on every call to
`policy_private_scope_label`.

## `extract_mcp_response` → `Cow<'_, Value>` (`labels/mod.rs`)

Common path now borrows; only the rare MCP-wrapped case allocates:

```rust
// Before
pub(crate) fn extract_mcp_response(response: &Value) -> Value {
    // ...
    response.clone()  // full payload deep-copy every call
}

// After
pub(crate) fn extract_mcp_response(response: &Value) -> Cow<'_, Value> {
    // ...
    Cow::Borrowed(response)  // zero allocation on common path
    // wrapped path: Cow::Owned(parsed)
}
```

Call site updates in `response_items.rs` where `Value` (not `Cow`) is
required: `actual_response.clone()` → `actual_response.as_ref().clone()`
and `&actual_response` → `actual_response.as_ref()`. All other call
sites auto-deref through `Deref<Target = Value>` unchanged.

## `first_matching_scope` → `Option<&'a PolicyScopeEntry>`
(`labels/helpers.rs`)

Removes `.cloned()` to eliminate 3 `String` allocations per lookup.
`policy_private_scope_label` (the only call site) is unaffected —
`ScopeKind` is `Copy` and field access works identically through a
reference.

```rust
// Before
fn first_matching_scope(owner: &str, repo: &str, ctx: &PolicyContext) -> Option<PolicyScopeEntry> {
    ctx.scopes.iter().find(|scope| { /* ... */ }).cloned()
}

// After
fn first_matching_scope<'a>(owner: &str, repo: &str, ctx: &'a PolicyContext) -> Option<&'a PolicyScopeEntry> {
    ctx.scopes.iter().find(|scope| { /* ... */ })
}
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build3904760875/b513/launcher.test
/tmp/go-build3904760875/b513/launcher.test
-test.testlogfile=/tmp/go-build3904760875/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s go_.�� ache/go/1.25.9/x-errorsas
etut/NpEHhtvPW_A-ifaceassert x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet`
(dns block)
> - Triggering command: `/tmp/go-build100690393/b509/launcher.test
/tmp/go-build100690393/b509/launcher.test
-test.testlogfile=/tmp/go-build100690393/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true -bool
72e203ec55626255a1c2f6351011f81be538b3bb6463e1a9d5c
ker/cli-plugins/docker-compose 72e203ec55626255bash` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3904760875/b495/config.test
/tmp/go-build3904760875/b495/config.test
-test.testlogfile=/tmp/go-build3904760875/b495/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build3904760875/b396/vet.cfg 1154246/b196/_pkg_.a -trimpath
x_amd64/vet -p go.opentelemetry-atomic -lang=go1.25 x_amd64/vet go_.��
.cfg knP4/DXqMOEsmzZ1-ifaceassert x_amd64/vet --gdwarf-5 --64 -o
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build100690393/b491/config.test
/tmp/go-build100690393/b491/config.test
-test.testlogfile=/tmp/go-build100690393/b491/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true 4760875/b504/_pkg_.a
stmain.go docker-compose
by/32b5d288a6552/usr/lib/open-iscsi/net-interface-handler -ifaceassert
-nilfunc docker-compose n-me�� b6b9402ad1484ea3 -buildtags
&#34;CURL_CA_BUNDLE=/-id by/181260d18b4dc/usr/bin/networkctl
-ifaceassert -nilfunc iginal` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build3904760875/b513/launcher.test
/tmp/go-build3904760875/b513/launcher.test
-test.testlogfile=/tmp/go-build3904760875/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s go_.�� ache/go/1.25.9/x-errorsas
etut/NpEHhtvPW_A-ifaceassert x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet`
(dns block)
> - Triggering command: `/tmp/go-build100690393/b509/launcher.test
/tmp/go-build100690393/b509/launcher.test
-test.testlogfile=/tmp/go-build100690393/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true -bool
72e203ec55626255a1c2f6351011f81be538b3bb6463e1a9d5c
ker/cli-plugins/docker-compose 72e203ec55626255bash` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build3904760875/b513/launcher.test
/tmp/go-build3904760875/b513/launcher.test
-test.testlogfile=/tmp/go-build3904760875/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s go_.�� ache/go/1.25.9/x-errorsas
etut/NpEHhtvPW_A-ifaceassert x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet`
(dns block)
> - Triggering command: `/tmp/go-build100690393/b509/launcher.test
/tmp/go-build100690393/b509/launcher.test
-test.testlogfile=/tmp/go-build100690393/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true -bool
72e203ec55626255a1c2f6351011f81be538b3bb6463e1a9d5c
ker/cli-plugins/docker-compose 72e203ec55626255bash` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build3904760875/b522/mcp.test
/tmp/go-build3904760875/b522/mcp.test
-test.testlogfile=/tmp/go-build3904760875/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -o 64/src/net -trimpath
x_amd64/vet -p net/http/httptes--version -lang=go1.25 x_amd64/vet .cfg��
/opt/hostedtoolcache/go/1.25.9/xgo1.25.9 1154246/b166/ x_amd64/vet
--gdwarf-5 --64` (dns block)
> - Triggering command: `/tmp/go-build100690393/b518/mcp.test
/tmp/go-build100690393/b518/mcp.test
-test.testlogfile=/tmp/go-build100690393/b518/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true -bool y
/usr/local/bin/bash ntime.v2.task/mobash -ifaceassert 2d7/log.json bash
/usr��
6788dd938a942ab2a742ecfee664e61b/run/containerd/io.containerd.runtime.v2.task/moby/1166b6fa98e14docker
-tests /usr/sbin/bash 2d7 /tmp/go-build410/usr/bin/runc 2d7/init.pid
bash` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request May 7, 2026
`internal/mcp/tool_result.go` repeated the same marshal-to-`TextContent`
fallback in four branches of `ConvertToCallToolResult` /
`convertMapToCallToolResult`. This change centralizes that behavior so
fallback handling stays consistent as the conversion logic evolves.

- **Refactor fallback construction**
  - Extract `marshalValueToTextContentResult` to own the shared:
    - `json.Marshal(...)`
- `sdk.CallToolResult{Content: []sdk.Content{&sdk.TextContent{...}}}`
    - error wrapping on marshal failure
  - Replace the four duplicated fallback blocks with calls to the helper

- **Behavior preserved across existing fallback paths**
  - direct array input (`[]interface{}`)
  - scalar / non-structured input
  - map input with missing or `nil` `content`
  - map input with unrecognized `content` shape

- **Focused coverage**
- Add a unit test for the `content: nil` map case to ensure it still
falls back to raw text wrapping

```go
func marshalValueToTextContentResult(value interface{}) (*sdk.CallToolResult, error) {
	dataBytes, err := json.Marshal(value)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal backend result: %w", err)
	}
	return &sdk.CallToolResult{
		Content: []sdk.Content{&sdk.TextContent{Text: string(dataBytes)}},
	}, nil
}
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build1542213297/b513/launcher.test
/tmp/go-build1542213297/b513/launcher.test
-test.testlogfile=/tmp/go-build1542213297/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1542213297/b445/vet.cfg g_.a -I x_amd64/vet --gdwarf-5
ls/insecure -o x_amd64/vet -qui�� .cfg /tmp/go-build418-ifaceassert
x_amd64/vet . .io/otel/semconv-atomic x86_64-linux-gnu-bool x_amd64/vet`
(dns block)
> - Triggering command: `/tmp/go-build2637788630/b513/launcher.test
/tmp/go-build2637788630/b513/launcher.test
-test.testlogfile=/tmp/go-build2637788630/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s .o .o .o .o .o .o
f07e34dca1.build--exclude-standard lib/rustlib/x86_--others lib/��
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libobject-926daa94a00ee327.rlib
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libmemchr-48d5b0db80402653.rlib
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libaddr2line-3367f26bd486b29d.rlib
(compatibility issue with Go 1.25.0). Continuing with other
checks...&#34;; \
elif command -v golan lib/rustlib/x86_--norc lib/rustlib/x86_--noprofile
05ed-cgu.00.rcgu.o` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1542213297/b495/config.test
/tmp/go-build1542213297/b495/config.test
-test.testlogfile=/tmp/go-build1542213297/b495/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1542213297/b393/vet.cfg uf@v1.36.11/protoadapt/convert.go
om/tetratelabs/wazero@v1.11.0/internal/fsapi/polgoogle.golang.org/grpc/balancer/pickfirst/intern-atomic
x_amd64/vet 4460836/b150/ --64` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build1542213297/b513/launcher.test
/tmp/go-build1542213297/b513/launcher.test
-test.testlogfile=/tmp/go-build1542213297/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1542213297/b445/vet.cfg g_.a -I x_amd64/vet --gdwarf-5
ls/insecure -o x_amd64/vet -qui�� .cfg /tmp/go-build418-ifaceassert
x_amd64/vet . .io/otel/semconv-atomic x86_64-linux-gnu-bool x_amd64/vet`
(dns block)
> - Triggering command: `/tmp/go-build2637788630/b513/launcher.test
/tmp/go-build2637788630/b513/launcher.test
-test.testlogfile=/tmp/go-build2637788630/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s .o .o .o .o .o .o
f07e34dca1.build--exclude-standard lib/rustlib/x86_--others lib/��
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libobject-926daa94a00ee327.rlib
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libmemchr-48d5b0db80402653.rlib
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libaddr2line-3367f26bd486b29d.rlib
(compatibility issue with Go 1.25.0). Continuing with other
checks...&#34;; \
elif command -v golan lib/rustlib/x86_--norc lib/rustlib/x86_--noprofile
05ed-cgu.00.rcgu.o` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build1542213297/b513/launcher.test
/tmp/go-build1542213297/b513/launcher.test
-test.testlogfile=/tmp/go-build1542213297/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/tmp/go-build1542213297/b445/vet.cfg g_.a -I x_amd64/vet --gdwarf-5
ls/insecure -o x_amd64/vet -qui�� .cfg /tmp/go-build418-ifaceassert
x_amd64/vet . .io/otel/semconv-atomic x86_64-linux-gnu-bool x_amd64/vet`
(dns block)
> - Triggering command: `/tmp/go-build2637788630/b513/launcher.test
/tmp/go-build2637788630/b513/launcher.test
-test.testlogfile=/tmp/go-build2637788630/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s .o .o .o .o .o .o
f07e34dca1.build--exclude-standard lib/rustlib/x86_--others lib/��
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libobject-926daa94a00ee327.rlib
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libmemchr-48d5b0db80402653.rlib
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libaddr2line-3367f26bd486b29d.rlib
(compatibility issue with Go 1.25.0). Continuing with other
checks...&#34;; \
elif command -v golan lib/rustlib/x86_--norc lib/rustlib/x86_--noprofile
05ed-cgu.00.rcgu.o` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build1542213297/b522/mcp.test
/tmp/go-build1542213297/b522/mcp.test
-test.testlogfile=/tmp/go-build1542213297/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -o .cfg -trimpath x_amd64/vet -p
vendor/golang.or/usr/bin/runc -lang=go1.25 x_amd64/vet .cfg��
4460836/b392/_pkg_.a -I x_amd64/vet --gdwarf-5 g/protobuf/inter-o -o
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build495322174/b001/mcp.test
/tmp/go-build495322174/b001/mcp.test
-test.testlogfile=/tmp/go-build495322174/b001/testlog.txt
-test.paniconexit0 -test.timeout=10m0s
/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.07.rcgu.o
/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.08.rcgu.o
/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.09.rcgu.o
/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.10.rcgu.o
/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.11.rcgu.o
/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/debug/��
/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.13.rcgu.o
/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/debug/deps/serde_derive-bdc7cd22a58a5141.serde_derive.12123747d8da05ed-cgu.14.rcgu.o
64-u�� 64-REDACTED-linux-gnu/lib/libminiz_oxide-2b6a8d2f6e1dc71b.rlib
64-REDACTED-linux-gnu/lib/libadler2-39ffdbc27c978ccc.rlib
/usr/libexec/doc-Wl,-Bstatic by/405f41b9e5ffacc
42ce6344f8114eba-Wl,--version-script=/home/REDACTED/work/gh-aw-mcpg/gh-aw-mcpg/guards/github-guard/rust-guard/target/debug/deps/rustcsdpj1U/list
-importcfg 0cd/log.json` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request May 7, 2026
…lback (#5243)

The gateway uses `tetratelabs/wazero` to run WASM DIFC guards
in-process. This updates the guard runtime to persist compilation
artifacts across restarts and makes the allocator fallback path more
explicit and diagnosable.

- **Persisted wazero cache**
  - adds `--wasm-cache-dir` and `MCP_GATEWAY_WASM_CACHE_DIR`
  - defaults the cache to `<log-dir>/wazero-cache`
- configures the shared global wazero compilation cache during gateway
and proxy startup
  - keeps cache lifecycle explicit in shutdown/cleanup paths

- **Safer guard execution behavior**
- emits a one-time warning per guard when `alloc` / `dealloc` exports
are missing and execution falls back to direct linear-memory placement
- keeps the existing fallback behavior, but makes the risk visible to
guard authors/operators
- uses the guard name as the instantiated WASM module name instead of
the hard-coded `"guard"`

- **Documentation of memory ownership**
- documents that memory ceilings must be declared in the WASM module
itself
- clarifies that the gateway does not impose an additional host-side
linear-memory cap

- **Coverage updates**
- adds focused tests for global cache reconfiguration and the new CLI
flag/default resolution

```go
cmd.Flags().StringVar(
    &wasmCacheDir,
    "wasm-cache-dir",
    resolveWasmCacheDir(false, "", defaultProxyLogDir),
    "Directory for disk-backed wazero compilation cache (default: <log-dir>/wazero-cache)",
)
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build904193801/b509/launcher.test
/tmp/go-build904193801/b509/launcher.test
-test.testlogfile=/tmp/go-build904193801/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
uf@v1.36.11/type-errorsas om/segmentio/asm-ifaceassert x_amd64/vet
/tmp/go-build119/opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linux_amd64/vet
ce/internal/obse-unsafeptr=false x86_64-linux-gnu-unreachable=false
x_amd64/vet 3325�� g_.a
ache/go/1.25.9/x64/src/compress/flate/deflate.go-nolocalimports
x_amd64/vet -I ntio/asm/ascii -imultiarch x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build1634526129/b513/launcher.test
/tmp/go-build1634526129/b513/launcher.test
-test.testlogfile=/tmp/go-build1634526129/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build904193801/b491/config.test
/tmp/go-build904193801/b491/config.test
-test.testlogfile=/tmp/go-build904193801/b491/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
@v1.43.0/semconv/v1.27.0/attribute_group.go
@v1.43.0/semconv/v1.27.0/doc.go x_amd64/vet --gdwarf-5 --64 -o
x_amd64/vet 3325�� g_.a
ache/go/1.25.9/x64/src/log/slog/internal/buffer/-nolocalimports
x_amd64/vet --gdwarf-5 telabs/wazero/in-atomic -o x_amd64/vet` (dns
block)
> - Triggering command: `/tmp/go-build1634526129/b495/config.test
/tmp/go-build1634526129/b495/config.test
-test.testlogfile=/tmp/go-build1634526129/b495/testlog.txt
-test.paniconexit0 -test.timeout=10m0s 7478�� echo &#34;Running li-nxv
cfg ep/bin/linux-x64/rg -c=4 -nolocalimports -importcfg
ep/bin/linux-x64-buildtags 7478�� /tmp/go-build302-errorsas
/home/REDACTED/go/-ifaceassert x_amd64/compile 64/src/runtime/cbash
7RwcO3vCT de/node/bin/as x_amd64/compile` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build904193801/b509/launcher.test
/tmp/go-build904193801/b509/launcher.test
-test.testlogfile=/tmp/go-build904193801/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
uf@v1.36.11/type-errorsas om/segmentio/asm-ifaceassert x_amd64/vet
/tmp/go-build119/opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linux_amd64/vet
ce/internal/obse-unsafeptr=false x86_64-linux-gnu-unreachable=false
x_amd64/vet 3325�� g_.a
ache/go/1.25.9/x64/src/compress/flate/deflate.go-nolocalimports
x_amd64/vet -I ntio/asm/ascii -imultiarch x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build1634526129/b513/launcher.test
/tmp/go-build1634526129/b513/launcher.test
-test.testlogfile=/tmp/go-build1634526129/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build904193801/b509/launcher.test
/tmp/go-build904193801/b509/launcher.test
-test.testlogfile=/tmp/go-build904193801/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true
uf@v1.36.11/type-errorsas om/segmentio/asm-ifaceassert x_amd64/vet
/tmp/go-build119/opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linux_amd64/vet
ce/internal/obse-unsafeptr=false x86_64-linux-gnu-unreachable=false
x_amd64/vet 3325�� g_.a
ache/go/1.25.9/x64/src/compress/flate/deflate.go-nolocalimports
x_amd64/vet -I ntio/asm/ascii -imultiarch x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build1634526129/b513/launcher.test
/tmp/go-build1634526129/b513/launcher.test
-test.testlogfile=/tmp/go-build1634526129/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build904193801/b518/mcp.test
/tmp/go-build904193801/b518/mcp.test
-test.testlogfile=/tmp/go-build904193801/b518/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true .cfg
rg/x/net@v0.52.0-ifaceassert x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet
.cfg�� 3325167/b384/_pkg_.a -I x_amd64/vet --gdwarf-5 g/grpc/resolver -o
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build1634526129/b522/mcp.test
/tmp/go-build1634526129/b522/mcp.test
-test.testlogfile=/tmp/go-build1634526129/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s /tmp��` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
lpcox added a commit that referenced this pull request May 8, 2026
Some GitHub MCP tool responses carry large repeated fields that dominate
token usage, notably `list_code_scanning_alerts` where `rule.help`
repeats full CWE help text on every alert. This change adds a
gateway-side, per-tool jq filter so responses can be trimmed before they
reach the agent and before payload preview/schema generation runs.

- **What changed**
- Added `tool_response_filters` to per-server config for both TOML and
stdin JSON configs.
- Filters are keyed by backend tool name and contain a jq expression
applied to that tool’s response payload.

- **Config + fail-fast validation**
  - jq expressions are parsed/compiled during config validation.
- Invalid or empty filters fail startup/config load instead of surfacing
at request time.

- **Response pipeline**
  - Applied configured filters in the jq middleware before:
    - inline tool response serialization
    - large-payload storage / preview generation
    - schema extraction
- Preserves existing metadata and follow-up content handling while
rewriting the primary JSON payload.

- **Result**
- Enables targeted response shaping for high-volume tools without
changing the upstream MCP server.
  - Keeps the behavior declarative and server-local in gateway config.

Example:

```toml
[servers.github]
command = "docker"
args = ["run", "--rm", "-i", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server:latest"]

[servers.github.tool_response_filters]
list_code_scanning_alerts = "map(del(.rule.help))"
list_secret_scanning_alerts = "map(del(.push_protection_bypassed_by))"
```

That allows responses like:

```json
[
  {
    "number": 101,
    "rule": {
      "id": "go/sql-injection",
      "help": "very long repeated CWE help text"
    }
  }
]
```

to be rewritten as:

```json
[
  {
    "number": 101,
    "rule": {
      "id": "go/sql-injection"
    }
  }
]
```

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `example.com`
> - Triggering command: `/tmp/go-build302098926/b509/launcher.test
/tmp/go-build302098926/b509/launcher.test
-test.testlogfile=/tmp/go-build302098926/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true ache/go/1.25.9/x-p
ache/go/1.25.9/xgoogle.golang.org/grpc/internal/metadata x_amd64/asm`
(dns block)
> - Triggering command: `/tmp/go-build3754274398/b513/launcher.test
/tmp/go-build3754274398/b513/launcher.test
-test.testlogfile=/tmp/go-build3754274398/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s e=/t�� t0 m0s ash -errorsas
-ifaceassert -nilfunc 098926/b514/importcfg -ato��
k/gh-aw-mcpg/gh-aw-mcpg/internal/logger/sanitizego1.25.9
k/gh-aw-mcpg/gh-aw-mcpg/internal/logger/sanitize-c=4
/opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linu-nolocalimports
-errorsas -ifaceassert -nilfunc
/opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linu/tmp/go-build2478948471/b264/_testmain.go`
(dns block)
> - Triggering command: `/tmp/go-build2307936139/b513/launcher.test
/tmp/go-build2307936139/b513/launcher.test
-test.testlogfile=/tmp/go-build2307936139/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s know��
known-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libobject-926daa94a00ee327.rlib
known-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libmemchr-48d5b0db80402653.rlib
known-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libaddr2line-3367f26bd486b29d.rlib
known-linux-gnu/bash known-linux-gnu//usr/bin/runc
known-linux-gnu/--version ive.12123747d8da05ed-cgu.00.rcgu.o ive.��
l/middleware/jqschema_test.go ive.12123747d8da05ed-cgu.03.rcgu.o
x_amd64/compile ive.12123747d8dabash ive.12123747d8da--norc
ive.12123747d8da--noprofile x_amd64/compile` (dns block)
> - `invalid-host-that-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build302098926/b491/config.test
/tmp/go-build302098926/b491/config.test
-test.testlogfile=/tmp/go-build302098926/b491/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true ternal/wasmdebug-p
ternal/wasmdebuggoogle.golang.org/grpc/metadata x_amd64/compile` (dns
block)
> - Triggering command: `/tmp/go-build2478948471/b264/config.test
/tmp/go-build2478948471/b264/config.test
-test.testlogfile=/tmp/go-build2478948471/b264/testlog.txt
-test.paniconexit0 -test.timeout=10m0s 0989��
uf@v1.36.11/reflect/protoreflect-errorsas
uf@v1.36.11/reflect/protoreflect-ifaceassert x_amd64/vet --gdwarf-5
ernal/x -o x_amd64/vet rtcf�� 1.80.0/internal/-errorsas
1.80.0/internal/-ifaceassert 64/pkg/tool/linu-nilfunc --gdwarf-5 --64 -o
64/pkg/tool/linu-tests` (dns block)
> - Triggering command: `/tmp/go-build2144274392/b264/config.test
/tmp/go-build2144274392/b264/config.test
-test.testlogfile=/tmp/go-build2144274392/b264/testlog.txt
-test.paniconexit0 -test.timeout=10m0s .o .o .o .o .o .o
69327bc0f.build_0fe53110ba95802fc3eedafe42b5f4ea0d304545:internal/config/validation.go
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libstd-46d936097e8c5b85.rlib
lib/��
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libobject-926daa94a00ee327.rlib
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libmemchr-48d5b0db80402653.rlib
lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libaddr2line-3367f26bd486b29d.rlib
lib/rustlib/x86_/bin/sh lib/rustlib/x86_-c lib/rustlib/x86_echo &#34;
test-serena - Run Serena MCP Server tests (direct connection)&#34;
05ed-cgu.00.rcgu.o` (dns block)
> - `nonexistent.local`
> - Triggering command: `/tmp/go-build302098926/b509/launcher.test
/tmp/go-build302098926/b509/launcher.test
-test.testlogfile=/tmp/go-build302098926/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true ache/go/1.25.9/x-p
ache/go/1.25.9/xgoogle.golang.org/grpc/internal/metadata x_amd64/asm`
(dns block)
> - Triggering command: `/tmp/go-build3754274398/b513/launcher.test
/tmp/go-build3754274398/b513/launcher.test
-test.testlogfile=/tmp/go-build3754274398/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s e=/t�� t0 m0s ash -errorsas
-ifaceassert -nilfunc 098926/b514/importcfg -ato��
k/gh-aw-mcpg/gh-aw-mcpg/internal/logger/sanitizego1.25.9
k/gh-aw-mcpg/gh-aw-mcpg/internal/logger/sanitize-c=4
/opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linu-nolocalimports
-errorsas -ifaceassert -nilfunc
/opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linu/tmp/go-build2478948471/b264/_testmain.go`
(dns block)
> - Triggering command: `/tmp/go-build2307936139/b513/launcher.test
/tmp/go-build2307936139/b513/launcher.test
-test.testlogfile=/tmp/go-build2307936139/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s know��
known-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libobject-926daa94a00ee327.rlib
known-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libmemchr-48d5b0db80402653.rlib
known-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libaddr2line-3367f26bd486b29d.rlib
known-linux-gnu/bash known-linux-gnu//usr/bin/runc
known-linux-gnu/--version ive.12123747d8da05ed-cgu.00.rcgu.o ive.��
l/middleware/jqschema_test.go ive.12123747d8da05ed-cgu.03.rcgu.o
x_amd64/compile ive.12123747d8dabash ive.12123747d8da--norc
ive.12123747d8da--noprofile x_amd64/compile` (dns block)
> - `slow.example.com`
> - Triggering command: `/tmp/go-build302098926/b509/launcher.test
/tmp/go-build302098926/b509/launcher.test
-test.testlogfile=/tmp/go-build302098926/b509/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true ache/go/1.25.9/x-p
ache/go/1.25.9/xgoogle.golang.org/grpc/internal/metadata x_amd64/asm`
(dns block)
> - Triggering command: `/tmp/go-build3754274398/b513/launcher.test
/tmp/go-build3754274398/b513/launcher.test
-test.testlogfile=/tmp/go-build3754274398/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s e=/t�� t0 m0s ash -errorsas
-ifaceassert -nilfunc 098926/b514/importcfg -ato��
k/gh-aw-mcpg/gh-aw-mcpg/internal/logger/sanitizego1.25.9
k/gh-aw-mcpg/gh-aw-mcpg/internal/logger/sanitize-c=4
/opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linu-nolocalimports
-errorsas -ifaceassert -nilfunc
/opt/hostedtoolcache/go/1.25.9/x64/pkg/tool/linu/tmp/go-build2478948471/b264/_testmain.go`
(dns block)
> - Triggering command: `/tmp/go-build2307936139/b513/launcher.test
/tmp/go-build2307936139/b513/launcher.test
-test.testlogfile=/tmp/go-build2307936139/b513/testlog.txt
-test.paniconexit0 -test.timeout=10m0s know��
known-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libobject-926daa94a00ee327.rlib
known-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libmemchr-48d5b0db80402653.rlib
known-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libaddr2line-3367f26bd486b29d.rlib
known-linux-gnu/bash known-linux-gnu//usr/bin/runc
known-linux-gnu/--version ive.12123747d8da05ed-cgu.00.rcgu.o ive.��
l/middleware/jqschema_test.go ive.12123747d8da05ed-cgu.03.rcgu.o
x_amd64/compile ive.12123747d8dabash ive.12123747d8da--norc
ive.12123747d8da--noprofile x_amd64/compile` (dns block)
> - `this-host-does-not-exist-12345.com`
> - Triggering command: `/tmp/go-build302098926/b518/mcp.test
/tmp/go-build302098926/b518/mcp.test
-test.testlogfile=/tmp/go-build302098926/b518/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -test.v=true experimental.go
internal.go x_amd64/compile -p crypto/ecdh -lang=go1.25 x_amd64/compile
-I /opt/hostedtoolcache/go/1.25.9/x-p cfg x_amd64/vet --gdwarf-5 --64 -o
x_amd64/vet` (dns block)
> - Triggering command: `/tmp/go-build3754274398/b522/mcp.test
/tmp/go-build3754274398/b522/mcp.test
-test.testlogfile=/tmp/go-build3754274398/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s -ato�� -bool -buildtags bash
-errorsas -ifaceassert -nilfunc /opt/hostedtoolcache/go/1.25.9/x--revs
-ato�� -bool -buildtags x_amd64/link -errorsas -ifaceassert -nilfunc
x_amd64/link` (dns block)
> - Triggering command: `/tmp/go-build2307936139/b522/mcp.test
/tmp/go-build2307936139/b522/mcp.test
-test.testlogfile=/tmp/go-build2307936139/b522/testlog.txt
-test.paniconexit0 -test.timeout=10m0s know��
known-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libobject-926daa94a00ee327.rlib
known-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libmemchr-48d5b0db80402653.rlib
known-linux-gnu/lib/rustlib/x86_64-REDACTED-linux-gnu/lib/libaddr2line-3367f26bd486b29d.rlib
known-linux-gnu/runc jvhawl2nskseooqp--version
z8tylr32cgwnziux.0lr3v9a.rcgu.o ruczucboywd9kbz6.0lr3v9a.rcgu.o aiea��
l/server/tool_registry.go p1agk9if6se1ud54.0lr3v9a.rcgu.o
fc88gtczrpthgg1u.0lr3v9a.rcgu.o 6uc4ma8f604u2vi6bash
5vmlrtxer9j2lnp9--norc zucrirrh7hnf4z1l--noprofile
o4qlefxtp7qruodt.0lr3v9a.rcgu.o` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent)
(admins only)
>
> </details>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants