From ca1c1704ffa8b7cdd5a37bec0f4210fed1ea1289 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Jul 2026 04:44:02 +0000 Subject: [PATCH 1/2] Initial plan From 7e590e6a12c333f372d3e0772865d9e12e55fe51 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Jul 2026 05:19:21 +0000 Subject: [PATCH 2/2] Add dedicated loggers to 5 pkg files for targeted debug tracing Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/bootstrap_profile_github_app.go | 7 +++++++ pkg/intent/policy.go | 14 +++++++++++++- pkg/workflow/copilot_inline_driver.go | 6 ++++++ pkg/workflow/mcp_setup_safe_outputs.go | 6 ++++++ pkg/workflow/permissions_compiler_validator.go | 8 ++++++++ 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/pkg/cli/bootstrap_profile_github_app.go b/pkg/cli/bootstrap_profile_github_app.go index ccebda8c42d..31bb7318eb3 100644 --- a/pkg/cli/bootstrap_profile_github_app.go +++ b/pkg/cli/bootstrap_profile_github_app.go @@ -14,16 +14,21 @@ import ( "charm.land/huh/v2" "github.com/github/gh-aw/pkg/console" + "github.com/github/gh-aw/pkg/logger" "github.com/github/gh-aw/pkg/repoutil" "github.com/github/gh-aw/pkg/workflow" ) +var githubAppBootstrapLog = logger.New("cli:bootstrap_profile_github_app") + func runBootstrapGitHubAppAction(ctx context.Context, repo string, action repositoryPackageBootstrapAction, state *bootstrapProfileExistingState) (*bootstrapCreatedGitHubApp, error) { _, hasVar := state.variables[action.AppIDVariable] _, hasSecret := state.secrets[action.PrivateKeySecret] if hasVar && hasSecret { + githubAppBootstrapLog.Printf("GitHub App already configured: appIDVar=%s privateKeySecret=%s, skipping", action.AppIDVariable, action.PrivateKeySecret) return nil, nil } + githubAppBootstrapLog.Printf("Running GitHub App bootstrap action: repo=%s appIDVar=%s", repo, action.AppIDVariable) overrides, err := loadBootstrapGitHubAppOverrides() if err != nil { @@ -88,6 +93,7 @@ func handleBootstrapGitHubAppExistingFlow(ctx context.Context, repo string, acti if clientID == "" && privateKey == "" && action.Mode != "existing" && overrides.Mode != "existing" { return false, nil } + githubAppBootstrapLog.Printf("Applying existing GitHub App credentials: repo=%s hasClientID=%v hasPrivateKey=%v", repo, clientID != "", privateKey != "") resolvedClientID, resolvedPrivateKey, err := completeExistingGitHubAppCredentials(clientID, privateKey, action, repo) if err != nil { return false, err @@ -389,6 +395,7 @@ func waitForBootstrapGitHubAppInstallation(ctx context.Context, repo string, cre if createdApp == nil || createdApp.InstallURL == "" || createdApp.Slug == "" { return nil } + githubAppBootstrapLog.Printf("Waiting for GitHub App installation: repo=%s slug=%s installURL=%s", repo, createdApp.Slug, createdApp.InstallURL) bootstrapLog.Printf("Polling for GitHub App installation: repo=%s, slug=%s", repo, createdApp.Slug) deadlineTimer := time.NewTimer(bootstrapProfileManifestTimeout) defer deadlineTimer.Stop() diff --git a/pkg/intent/policy.go b/pkg/intent/policy.go index 9ba98979e7a..444c09c464f 100644 --- a/pkg/intent/policy.go +++ b/pkg/intent/policy.go @@ -1,6 +1,12 @@ package intent -import "slices" +import ( + "slices" + + "github.com/github/gh-aw/pkg/logger" +) + +var policyLog = logger.New("intent:policy") // autonomyRank maps autonomy levels to a restriction rank (higher = more restrictive). // propose_only is the most restrictive (agents may only propose changes, not execute); @@ -98,9 +104,11 @@ type PolicyCompiler struct { // rules are merged with stricter-wins semantics. If no rules match, the safest // default policy is returned. func (c PolicyCompiler) Compile(rec IntentRecord, repo RepositoryContext) ExecutionPolicy { + policyLog.Printf("Compiling policy: status=%s rules=%d", rec.Status, len(c.Rules)) // Fail-closed for indeterminate statuses: unlinked and ambiguous records // must never receive a relaxed policy from a matching wildcard rule. if rec.Status == AttributionUnlinked || rec.Status == AttributionAmbiguous { + policyLog.Printf("Fail-closed for indeterminate status=%s, returning safest default policy", rec.Status) return safestDefaultPolicy() } @@ -118,14 +126,18 @@ func (c PolicyCompiler) Compile(rec IntentRecord, repo RepositoryContext) Execut accumulated = deepCopyPolicy(rule.Set) accumulated.RuleIDs = []string{rule.ID} matched = true + policyLog.Printf("First matching rule: id=%s autonomy=%s write_scope=%s", rule.ID, rule.Set.Autonomy, rule.Set.WriteScope) } else { accumulated = mergePolicy(accumulated, rule.Set) accumulated.RuleIDs = append(accumulated.RuleIDs, rule.ID) + policyLog.Printf("Merging additional rule: id=%s", rule.ID) } } if !matched { + policyLog.Print("No rules matched, returning safest default policy") return safestDefaultPolicy() } + policyLog.Printf("Compiled policy: autonomy=%s write_scope=%s human_approval=%v matched_rules=%d", accumulated.Autonomy, accumulated.WriteScope, accumulated.HumanApprovalRequired, len(accumulated.RuleIDs)) return accumulated } diff --git a/pkg/workflow/copilot_inline_driver.go b/pkg/workflow/copilot_inline_driver.go index efeb1f3ae0c..e0ca070a6cd 100644 --- a/pkg/workflow/copilot_inline_driver.go +++ b/pkg/workflow/copilot_inline_driver.go @@ -5,8 +5,11 @@ import ( "strings" "github.com/github/gh-aw/pkg/constants" + "github.com/github/gh-aw/pkg/logger" ) +var inlineDriverLog = logger.New("workflow:copilot_inline_driver") + const ( inlineCopilotSDKDriverDir = ".gh-aw/copilot-sdk" inlineCopilotSDKDriverWrapperPath = inlineCopilotSDKDriverDir + "/inline-driver" @@ -45,6 +48,7 @@ func (d *InlineEngineDriver) wrapperScript() string { return "" } + inlineDriverLog.Printf("Generating wrapper script for runtime=%s", d.Runtime) sourcePath := d.sourcePath() switch d.Runtime { case "node": @@ -121,6 +125,7 @@ func buildInlineCopilotSDKDriverWriteStep(workflowData *WorkflowData) GitHubActi inlineDriver := workflowData.EngineConfig.InlineDriver sourcePath := inlineDriver.sourcePath() if sourcePath == "" { + inlineDriverLog.Printf("No source path for inline driver runtime=%s, skipping write step", inlineDriver.Runtime) return GitHubActionStep{} } @@ -133,6 +138,7 @@ func buildInlineCopilotSDKDriverWriteStep(workflowData *WorkflowData) GitHubActi workflowData.ParsedFrontmatter.RuntimesTyped.Go.Version != "" { goVersion = workflowData.ParsedFrontmatter.RuntimesTyped.Go.Version } + inlineDriverLog.Printf("Building inline Copilot SDK driver write step: runtime=%s source=%s goVersion=%s", inlineDriver.Runtime, sourcePath, goVersion) step := GitHubActionStep{ " - name: Write Inline Copilot SDK Driver", diff --git a/pkg/workflow/mcp_setup_safe_outputs.go b/pkg/workflow/mcp_setup_safe_outputs.go index 58b0ac0f20a..0d0ab07015a 100644 --- a/pkg/workflow/mcp_setup_safe_outputs.go +++ b/pkg/workflow/mcp_setup_safe_outputs.go @@ -5,9 +5,12 @@ import ( "fmt" "strings" + "github.com/github/gh-aw/pkg/logger" "github.com/github/gh-aw/pkg/sliceutil" ) +var safeOutputsSetupLog = logger.New("workflow:mcp_setup_safe_outputs") + // safeOutputsSecretEnvPrefix is prepended to secret names when generating step env var names for // safe-outputs config placeholders. The prefix avoids accidental collisions between a workflow // secret name and a pre-existing step env var (e.g. a secret named DEBUG or @@ -20,9 +23,11 @@ func generateSafeOutputsSetup(c *Compiler, yaml *strings.Builder, safeOutputConf if !HasSafeOutputsEnabled(workflowData.SafeOutputs) { return } + safeOutputsSetupLog.Printf("Generating safe outputs setup: configLen=%d", len(safeOutputConfig)) yaml.WriteString(" - name: Generate Safe Outputs Config\n") sanitizedConfig, envKeys, envValues := buildSafeOutputsConfigRuntimeData(safeOutputConfig) if len(envKeys) > 0 { + safeOutputsSetupLog.Printf("Safe outputs config: envVars=%d", len(envKeys)) yaml.WriteString(" env:\n") writeStepEnvVars(yaml, envKeys, envValues) } @@ -111,6 +116,7 @@ func buildSafeOutputsConfigRuntimeEnvVars(safeOutputConfig string) ([]string, ma func buildSafeOutputsConfigRuntimeData(safeOutputConfig string) (string, []string, map[string]string) { sanitizedConfig := safeOutputConfig envKeys, envValues := buildSafeOutputsConfigRuntimeEnvVars(safeOutputConfig) + safeOutputsSetupLog.Printf("Building safe outputs config runtime data: envKeys=%d", len(envKeys)) for _, varName := range envKeys { value := envValues[varName] sanitizedConfig = strings.ReplaceAll(sanitizedConfig, value, "${"+varName+"}") diff --git a/pkg/workflow/permissions_compiler_validator.go b/pkg/workflow/permissions_compiler_validator.go index caec149d8bb..c9ed25532c7 100644 --- a/pkg/workflow/permissions_compiler_validator.go +++ b/pkg/workflow/permissions_compiler_validator.go @@ -41,8 +41,12 @@ import ( "fmt" "os" "strings" + + "github.com/github/gh-aw/pkg/logger" ) +var permissionsCompilerLog = logger.New("workflow:permissions_compiler_validator") + // validatePermissions validates all permission-related configuration: dangerous // permissions, GitHub App-only constraints, MCP app write restrictions, workflow_run // branch security, GitHub MCP toolset permissions, and the id-token write warning. @@ -204,6 +208,8 @@ func (c *Compiler) repositoryOwnerIsIndividualUser() bool { ownerType = strings.TrimSpace(string(output)) c.ownerTypeCache[owner] = ownerType workflowLog.Printf("Owner type for %q: %s", owner, ownerType) + } else { + permissionsCompilerLog.Printf("Owner type cache hit: owner=%s type=%q", owner, ownerType) } return ownerType == "User" } @@ -243,6 +249,8 @@ func validateOIDCPermissions(workflowData *WorkflowData, workflowPermissions *Pe return nil } + permissionsCompilerLog.Printf("OIDC permission check: requiresIDTokenWrite=true prefix=%q", errorPrefix) + if workflowPermissions == nil { return errors.New(errorPrefix + " requires permissions.id-token: write") }