Skip to content

Commit 8ade6cb

Browse files
Copilotpelikhan
andcommitted
Fix tools.github fallback edge cases and add missing MCP integration test entry
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
1 parent 3d9dc56 commit 8ade6cb

File tree

3 files changed

+85
-17
lines changed

3 files changed

+85
-17
lines changed

pkg/workflow/compiler_orchestrator_workflow.go

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -634,29 +634,37 @@ func applyTopLevelGitHubAppFallbacks(data *WorkflowData) {
634634
}
635635
}
636636

637-
// Fallback for tools.github (MCP GitHub token minting)
638-
if data.ParsedTools != nil && data.ParsedTools.GitHub != nil && data.ParsedTools.GitHub.GitHubApp == nil {
637+
// Fallback for tools.github (MCP GitHub token minting).
638+
// Skip when a custom github-token is already configured for the MCP server (token takes priority).
639+
if data.ParsedTools != nil && data.ParsedTools.GitHub != nil &&
640+
data.ParsedTools.GitHub.GitHubApp == nil && data.ParsedTools.GitHub.GitHubToken == "" {
639641
orchestratorWorkflowLog.Print("Applying top-level github-app fallback for tools.github")
640642
data.ParsedTools.GitHub.GitHubApp = fallback
641643
// Also update the raw tools map so applyDefaultTools (called from applyDefaults in
642644
// processOnSectionAndFilters) does not lose the fallback when it rebuilds ParsedTools
643645
// from the map.
644-
if github, ok := data.Tools["github"].(map[string]any); ok {
645-
appMap := map[string]any{
646-
"app-id": fallback.AppID,
647-
"private-key": fallback.PrivateKey,
648-
}
649-
if fallback.Owner != "" {
650-
appMap["owner"] = fallback.Owner
651-
}
652-
if len(fallback.Repositories) > 0 {
653-
repos := make([]any, len(fallback.Repositories))
654-
for i, r := range fallback.Repositories {
655-
repos[i] = r
656-
}
657-
appMap["repositories"] = repos
646+
appMap := map[string]any{
647+
"app-id": fallback.AppID,
648+
"private-key": fallback.PrivateKey,
649+
}
650+
if fallback.Owner != "" {
651+
appMap["owner"] = fallback.Owner
652+
}
653+
if len(fallback.Repositories) > 0 {
654+
repos := make([]any, len(fallback.Repositories))
655+
for i, r := range fallback.Repositories {
656+
repos[i] = r
658657
}
658+
appMap["repositories"] = repos
659+
}
660+
// Normalize data.Tools["github"] to a map so the github-app survives re-parsing.
661+
// Configurations like `github: true` are normalized here rather than losing the fallback.
662+
if github, ok := data.Tools["github"].(map[string]any); ok {
663+
// Already a map; inject into existing settings.
659664
github["github-app"] = appMap
665+
} else {
666+
// Non-map value (e.g. true/false) — create a fresh map preserving the enabled signal.
667+
data.Tools["github"] = map[string]any{"github-app": appMap}
660668
}
661669
}
662670

pkg/workflow/top_level_github_app_import_test.go

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,59 @@ This workflow's own top-level github-app takes precedence over the imported one.
137137
"Current workflow's github-app should take precedence over the imported one")
138138
}
139139

140-
// TestTopLevelGitHubAppImportActivation tests that a top-level github-app imported from a shared
140+
// TestTopLevelGitHubAppToolsGitHubTokenSkip tests that the fallback is NOT applied
141+
// to tools.github when a custom github-token is already configured for the MCP server.
142+
func TestTopLevelGitHubAppToolsGitHubTokenSkip(t *testing.T) {
143+
compiler := NewCompilerWithVersion("1.0.0")
144+
145+
// Use ParseWorkflowFile directly with inline frontmatter
146+
tmpDir := t.TempDir()
147+
workflowsDir := filepath.Join(tmpDir, ".github", "workflows")
148+
require.NoError(t, os.MkdirAll(workflowsDir, 0755))
149+
150+
// Workflow with top-level github-app but tools.github uses an explicit github-token
151+
workflowContent := `---
152+
on: issues
153+
permissions:
154+
contents: read
155+
github-app:
156+
app-id: ${{ vars.APP_ID }}
157+
private-key: ${{ secrets.APP_PRIVATE_KEY }}
158+
tools:
159+
github:
160+
mode: remote
161+
toolsets: [default]
162+
github-token: ${{ secrets.CUSTOM_PAT }}
163+
engine: copilot
164+
---
165+
166+
# Workflow With Explicit GitHub Token for MCP
167+
168+
When tools.github.github-token is set, the top-level github-app fallback should NOT override it.
169+
`
170+
mdPath := filepath.Join(workflowsDir, "main.md")
171+
require.NoError(t, os.WriteFile(mdPath, []byte(workflowContent), 0644))
172+
173+
origDir, err := os.Getwd()
174+
require.NoError(t, err)
175+
require.NoError(t, os.Chdir(workflowsDir))
176+
defer func() { _ = os.Chdir(origDir) }()
177+
178+
data, err := compiler.ParseWorkflowFile("main.md")
179+
require.NoError(t, err)
180+
181+
// The top-level github-app should be resolved at the top level
182+
require.NotNil(t, data.TopLevelGitHubApp, "TopLevelGitHubApp should be populated")
183+
184+
// But it must NOT be injected into tools.github because github-token takes precedence
185+
require.NotNil(t, data.ParsedTools, "ParsedTools should be populated")
186+
require.NotNil(t, data.ParsedTools.GitHub, "ParsedTools.GitHub should be populated")
187+
assert.Equal(t, "${{ secrets.CUSTOM_PAT }}", data.ParsedTools.GitHub.GitHubToken,
188+
"tools.github.github-token should be preserved")
189+
assert.Nil(t, data.ParsedTools.GitHub.GitHubApp,
190+
"tools.github.github-app should NOT be set when github-token is configured")
191+
}
192+
141193
// workflow is propagated to the activation job (reactions/status comments).
142194
func TestTopLevelGitHubAppImportActivation(t *testing.T) {
143195
compiler := NewCompilerWithVersion("1.0.0")

pkg/workflow/top_level_github_app_integration_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,14 @@ func TestTopLevelGitHubAppWorkflowFiles(t *testing.T) {
366366
"app-id: ${{ vars.ACTIVATION_APP_ID }}",
367367
},
368368
},
369+
{
370+
name: "tools.github MCP fallback workflow file",
371+
workflowFile: "../cli/workflows/test-top-level-github-app-mcp.md",
372+
expectContains: []string{
373+
"id: github-mcp-app-token",
374+
"app-id: ${{ vars.APP_ID }}",
375+
},
376+
},
369377
}
370378

371379
for _, tt := range tests {

0 commit comments

Comments
 (0)