Full Report
Function Inventory (by package)
| Package |
Files |
Primary purpose |
internal/auth/ |
2 |
Auth header parsing, agent ID generation |
internal/cmd/ |
11 |
CLI wiring, flag registration, startup |
internal/config/ |
16 |
Config parsing (TOML/JSON), validation, guard policy |
internal/difc/ |
11 |
DIFC labels, evaluation, pipeline decisions |
internal/envutil/ |
4 |
Env var access, Docker env args |
internal/githubhttp/ |
4 |
GitHub API helpers, visibility checks |
internal/guard/ |
9 |
Guard interface, WASM lifecycle/execution |
internal/httputil/ |
4 |
Reusable HTTP utilities, TLS config, response helpers |
internal/jqutil/ |
1 |
jq compiler options |
internal/launcher/ |
5 |
Process/session lifecycle, health monitoring |
internal/logger/ |
14 |
File/global/markdown/JSONL loggers |
internal/mcp/ |
6 |
MCP protocol transport and connection |
internal/middleware/ |
2 |
jq schema processing |
internal/proxy/ |
7 |
GitHub API proxying, DIFC filtering |
internal/sanitize/ |
1 |
Secret/data redaction |
internal/server/ |
22 |
Gateway HTTP handling, session/auth/guard init |
internal/syncutil/ |
2 |
Concurrency helpers |
internal/sys/ |
2 |
Container/Docker detection |
internal/tracing/ |
7 |
OTLP config resolution, provider setup |
internal/util/ |
6 |
Generic helpers (strings, random, truncate) |
Identified Issues
1. π΄ Duplicate: Workflow-repo visibility / "force public" policy logic split across cmd and server
Priority: High β affects security-sensitive policy enforcement code.
Files involved:
internal/cmd/proxy.go β proxyForcePublicReposIfNeeded()
internal/server/guard_visibility.go β shouldForcePublicRepos(), computeForcePublicRepos(), verifySinkVisibilityAtRuntime(), resolveWorkflowRepoVisibility()
internal/githubhttp/visibility.go β FetchRepoVisibility(), VerifySinkVisibility()
What's duplicated: Both proxy mode and gateway/server mode independently:
- Read
GITHUB_REPOSITORY
- Resolve the GitHub auth token
- Call
githubhttp.FetchRepoVisibility()
- Enforce "public repo β force public scope / visibility"
- Fail open on API failure
Code comparison:
// internal/cmd/proxy.go
func proxyForcePublicReposIfNeeded(ctx context.Context, policyJSON, token, apiURL string) string {
// reads GITHUB_REPOSITORY, calls FetchRepoVisibility, overrides policy JSON
}
// internal/server/guard_visibility.go
func computeForcePublicRepos() bool {
// reads GITHUB_REPOSITORY, calls FetchRepoVisibility, caches result
}
Recommendation:
Extract shared logic into internal/githubhttp/ or a new internal/policy/ package:
ResolveWorkflowRepoVisibility(ctx, apiURL, token) (RepoVisibility, bool)
ShouldForcePublicRepos(visibility RepoVisibility) bool
Let server/guard_visibility.go handle server-specific caching/logging; cmd/proxy.go delegates policy decision and JSON mutation to the shared helpers.
Estimated effort: 3-4 hours | Impact: Reduced duplication in security-sensitive policy path
2. π΄ Duplicate: Request body read/restore in security middleware
Priority: High β correctness-sensitive code in the auth/HMAC path.
Files involved:
internal/server/http_helpers.go β peekRequestBody() (the canonical helper)
internal/server/hmac.go β hmacMiddleware() (reimplements the same pattern inline)
Duplicate pattern (both do the same operation):
// http_helpers.go β peekRequestBody
b, err := io.ReadAll(origBody)
// ...
r.Body = io.NopCloser(bytes.NewReader(b))
// hmac.go β hmacMiddleware (inline)
body, err = io.ReadAll(r.Body)
// ...
r.Body = io.NopCloser(bytes.NewReader(body))
Recommendation:
- Use
peekRequestBody() from within hmacMiddleware(), or
- Promote
peekRequestBody() to internal/httputil as ReadAndRestoreRequestBody(*http.Request) ([]byte, error)
Estimated effort: 1 hour | Impact: Single implementation of body-restore in auth paths
3. π‘ Near-duplicate: HTTP response body reading scattered beyond httputil
Priority: Medium β httputil.ReadResponseBody* exists but is not consistently used.
Files involved:
internal/httputil/response.go β ReadResponseBody(), ReadResponseBodyStrict() (canonical)
internal/proxy/handler.go β forwardAndReadBody() (custom inline version)
internal/config/validation_schema.go β fetchSchema() (inline io.ReadAll + close)
internal/githubhttp/visibility.go β FetchRepoVisibility() (inline read pattern)
Pattern repeated in non-httputil locations:
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK { ... }
Recommendation:
Extend internal/httputil/response.go with variants:
ReadResponseBodyWithLimit(resp, maxBytes) β for bounded reads
DecodeJSONResponse(resp, target) β for JSON decode + close in one step
Migrate proxy.forwardAndReadBody and config.fetchSchema to use these helpers.
Estimated effort: 2-3 hours | Impact: Centralized HTTP response lifecycle
4. π‘ Outlier: Guard policy resolution/mutation logic split across two server files
Priority: Medium β security-sensitive, high-complexity area.
Files involved:
internal/server/guard_init.go β resolveGuardPolicy(), resolveWriteSinkPolicy(), ensureGuardInitialized()
internal/server/guard_visibility.go β overrideToPublicScope(), isServerExemptFromSinkVisibility(), validateSinkVisibilityExemptServers(), verifySinkVisibilityAtRuntime()
Issue: These 8+ functions form a coherent "guard policy resolution and mutation" subsystem, but are split between initialization lifecycle (guard_init.go) and runtime visibility enforcement (guard_visibility.go). The split makes it hard to reason about the complete policy pipeline.
Recommendation:
Create internal/server/guard_policy.go and move all policy resolution/mutation there:
resolveGuardPolicy()
resolveWriteSinkPolicy()
overrideToPublicScope()
shouldForcePublicRepos()
verifySinkVisibilityAtRuntime()
isServerExemptFromSinkVisibility()
Keep guard_init.go focused on guard construction, WASM loading, and registration.
Estimated effort: 2 hours (mechanical moves) | Impact: Improved navigability of security-critical policy code
5. π’ Scattered: Directory-flag completion registration repeated in cmd
Priority: Low β minor but consistent pattern.
Files involved:
internal/cmd/flags.go β registerFlagCompletions() marks directory flags for root command
internal/cmd/proxy.go β newProxyCmd() separately marks --tls-dir
Pattern:
Both manually call cmd.MarkFlagDirname(flagName) across multiple flags. The codebase already centralizes other flag groups (registerGuardsModeFlag, registerTracingFlags), but directory completions are not.
Recommendation:
Add a helper in internal/cmd/flags.go:
func markDirFlags(cmd *cobra.Command, names ...string) {
for _, name := range names {
_ = cmd.MarkFlagDirname(name)
}
}
Estimated effort: 30 minutes | Impact: Consistent with existing flag organization pattern
6. π’ Scattered: Generic file I/O helpers accumulating inside logger
Priority: Low (future-watch) β not urgent today, but trend is clear.
Files involved:
internal/logger/fileutil.go β atomicWriteFile(), writeJSONToFile(), initLogFile() (contains a TODO noting the generic nature of atomicWriteFile)
internal/proxy/tls.go β writePEM() (custom file-write with permissions)
internal/server/session.go β directory creation + file persistence
Issue: logger/fileutil.go already has a TODO noting atomicWriteFile should migrate when a second consumer appears. The codebase now has multiple independent file-writing patterns in non-logger code.
Recommendation:
When a third file-writing consumer appears, promote generics into a dedicated package:
internal/fileutil.AtomicWriteFile(path string, data []byte, perm os.FileMode) error
internal/fileutil.EnsureDir(path string) error
Estimated effort: 1-2 hours when triggered | Impact: Cleaner package boundaries
Refactoring Recommendations
Priority 1 β High Impact
- Extract shared force-public / visibility policy β consolidate
cmd/proxy.go + server/guard_visibility.go into githubhttp or internal/policy
- Centralize request body read/restore β use
peekRequestBody in hmac.go, promote to httputil
Priority 2 β Medium Impact
- Extend
httputil.response.go β migrate proxy.forwardAndReadBody and config.fetchSchema
- Create
server/guard_policy.go β consolidate guard policy resolution/mutation from two files
Priority 3 β Low/Future
- Add
markDirFlags helper in cmd
- Promote
atomicWriteFile to internal/fileutil when next consumer appears
Implementation Checklist
Analysis Metadata
- Total Go Files Analyzed: 144 (non-test,
internal/)
- Function Clusters Identified: 13 packages Γ ~avg 20 functions
- Outliers Found: 1 (guard policy split)
- Duplicates Detected: 3 (visibility policy, body read/restore, HTTP response body)
- Scattered Helpers: 2 (dir-flag completion, file I/O)
- Detection Method: Static function inventory + semantic clustering + targeted code comparison
- Analysis Date: 2026-07-20
π§ Semantic Function Clustering Analysis
Analysis of repository:
github/gh-aw-mcpgβ run Β§29779668922Executive Summary
Analyzed 144 non-test Go source files across
internal/. The codebase is generally well-organized with clear package boundaries. This report identifies 6 high-value refactoring opportunities β all concrete, actionable findings based on actual code duplication or semantic misplacement. No trivial or stylistic findings are included.Full Report
Function Inventory (by package)
internal/auth/internal/cmd/internal/config/internal/difc/internal/envutil/internal/githubhttp/internal/guard/internal/httputil/internal/jqutil/internal/launcher/internal/logger/internal/mcp/internal/middleware/internal/proxy/internal/sanitize/internal/server/internal/syncutil/internal/sys/internal/tracing/internal/util/Identified Issues
1. π΄ Duplicate: Workflow-repo visibility / "force public" policy logic split across
cmdandserverPriority: High β affects security-sensitive policy enforcement code.
Files involved:
internal/cmd/proxy.goβproxyForcePublicReposIfNeeded()internal/server/guard_visibility.goβshouldForcePublicRepos(),computeForcePublicRepos(),verifySinkVisibilityAtRuntime(),resolveWorkflowRepoVisibility()internal/githubhttp/visibility.goβFetchRepoVisibility(),VerifySinkVisibility()What's duplicated: Both proxy mode and gateway/server mode independently:
GITHUB_REPOSITORYgithubhttp.FetchRepoVisibility()Code comparison:
Recommendation:
Extract shared logic into
internal/githubhttp/or a newinternal/policy/package:ResolveWorkflowRepoVisibility(ctx, apiURL, token) (RepoVisibility, bool)ShouldForcePublicRepos(visibility RepoVisibility) boolLet
server/guard_visibility.gohandle server-specific caching/logging;cmd/proxy.godelegates policy decision and JSON mutation to the shared helpers.Estimated effort: 3-4 hours | Impact: Reduced duplication in security-sensitive policy path
2. π΄ Duplicate: Request body read/restore in security middleware
Priority: High β correctness-sensitive code in the auth/HMAC path.
Files involved:
internal/server/http_helpers.goβpeekRequestBody()(the canonical helper)internal/server/hmac.goβhmacMiddleware()(reimplements the same pattern inline)Duplicate pattern (both do the same operation):
Recommendation:
peekRequestBody()from withinhmacMiddleware(), orpeekRequestBody()tointernal/httputilasReadAndRestoreRequestBody(*http.Request) ([]byte, error)Estimated effort: 1 hour | Impact: Single implementation of body-restore in auth paths
3. π‘ Near-duplicate: HTTP response body reading scattered beyond
httputilPriority: Medium β
httputil.ReadResponseBody*exists but is not consistently used.Files involved:
internal/httputil/response.goβReadResponseBody(),ReadResponseBodyStrict()(canonical)internal/proxy/handler.goβforwardAndReadBody()(custom inline version)internal/config/validation_schema.goβfetchSchema()(inlineio.ReadAll+ close)internal/githubhttp/visibility.goβFetchRepoVisibility()(inline read pattern)Pattern repeated in non-httputil locations:
Recommendation:
Extend
internal/httputil/response.gowith variants:ReadResponseBodyWithLimit(resp, maxBytes)β for bounded readsDecodeJSONResponse(resp, target)β for JSON decode + close in one stepMigrate
proxy.forwardAndReadBodyandconfig.fetchSchemato use these helpers.Estimated effort: 2-3 hours | Impact: Centralized HTTP response lifecycle
4. π‘ Outlier: Guard policy resolution/mutation logic split across two
serverfilesPriority: Medium β security-sensitive, high-complexity area.
Files involved:
internal/server/guard_init.goβresolveGuardPolicy(),resolveWriteSinkPolicy(),ensureGuardInitialized()internal/server/guard_visibility.goβoverrideToPublicScope(),isServerExemptFromSinkVisibility(),validateSinkVisibilityExemptServers(),verifySinkVisibilityAtRuntime()Issue: These 8+ functions form a coherent "guard policy resolution and mutation" subsystem, but are split between initialization lifecycle (
guard_init.go) and runtime visibility enforcement (guard_visibility.go). The split makes it hard to reason about the complete policy pipeline.Recommendation:
Create
internal/server/guard_policy.goand move all policy resolution/mutation there:resolveGuardPolicy()resolveWriteSinkPolicy()overrideToPublicScope()shouldForcePublicRepos()verifySinkVisibilityAtRuntime()isServerExemptFromSinkVisibility()Keep
guard_init.gofocused on guard construction, WASM loading, and registration.Estimated effort: 2 hours (mechanical moves) | Impact: Improved navigability of security-critical policy code
5. π’ Scattered: Directory-flag completion registration repeated in
cmdPriority: Low β minor but consistent pattern.
Files involved:
internal/cmd/flags.goβregisterFlagCompletions()marks directory flags for root commandinternal/cmd/proxy.goβnewProxyCmd()separately marks--tls-dirPattern:
Both manually call
cmd.MarkFlagDirname(flagName)across multiple flags. The codebase already centralizes other flag groups (registerGuardsModeFlag,registerTracingFlags), but directory completions are not.Recommendation:
Add a helper in
internal/cmd/flags.go:Estimated effort: 30 minutes | Impact: Consistent with existing flag organization pattern
6. π’ Scattered: Generic file I/O helpers accumulating inside
loggerPriority: Low (future-watch) β not urgent today, but trend is clear.
Files involved:
internal/logger/fileutil.goβatomicWriteFile(),writeJSONToFile(),initLogFile()(contains a TODO noting the generic nature ofatomicWriteFile)internal/proxy/tls.goβwritePEM()(custom file-write with permissions)internal/server/session.goβ directory creation + file persistenceIssue:
logger/fileutil.goalready has a TODO notingatomicWriteFileshould migrate when a second consumer appears. The codebase now has multiple independent file-writing patterns in non-logger code.Recommendation:
When a third file-writing consumer appears, promote generics into a dedicated package:
internal/fileutil.AtomicWriteFile(path string, data []byte, perm os.FileMode) errorinternal/fileutil.EnsureDir(path string) errorEstimated effort: 1-2 hours when triggered | Impact: Cleaner package boundaries
Refactoring Recommendations
Priority 1 β High Impact
cmd/proxy.go+server/guard_visibility.gointogithubhttporinternal/policypeekRequestBodyinhmac.go, promote tohttputilPriority 2 β Medium Impact
httputil.response.goβ migrateproxy.forwardAndReadBodyandconfig.fetchSchemaserver/guard_policy.goβ consolidate guard policy resolution/mutation from two filesPriority 3 β Low/Future
markDirFlagshelper incmdatomicWriteFiletointernal/fileutilwhen next consumer appearsImplementation Checklist
ResolveWorkflowRepoVisibilityhelperpeekRequestBodyinhmacMiddlewarehttputil/response.goand migrate callersserver/guard_policy.govia mechanical movesmarkDirFlagshelperatomicWriteFileconsumers for future extractionAnalysis Metadata
internal/)References:
Warning
Firewall blocked 2 domains
The following domains were blocked by the firewall during workflow execution:
awmgmcpgproxy.golang.orgSee Network Configuration for more information.