From 9edd2a1d65f18e5044d68900616c35b96b252117 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Mar 2026 03:47:28 +0000 Subject: [PATCH 1/3] Initial plan From 06173f27f28c03fb35dd8c518169adc86ec2b5bc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Mar 2026 03:52:12 +0000 Subject: [PATCH 2/3] initial plan Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .../workflows/constraint-solving-potd.lock.yml | 11 +++++++---- actions/setup-cli/install.sh | 15 +++------------ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/.github/workflows/constraint-solving-potd.lock.yml b/.github/workflows/constraint-solving-potd.lock.yml index b125c171b69..d3098c919f0 100644 --- a/.github/workflows/constraint-solving-potd.lock.yml +++ b/.github/workflows/constraint-solving-potd.lock.yml @@ -66,7 +66,7 @@ jobs: GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI" GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} GH_AW_INFO_VERSION: "" - GH_AW_INFO_AGENT_VERSION: "0.0.420" + GH_AW_INFO_AGENT_VERSION: "0.0.421" GH_AW_INFO_WORKFLOW_NAME: "Constraint Solving — Problem of the Day" GH_AW_INFO_EXPERIMENTAL: "false" GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" @@ -301,7 +301,7 @@ jobs: git remote set-url origin "https://x-access-token:${{ github.token }}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" echo "Git configured with standard GitHub Actions identity" - name: Install GitHub Copilot CLI - run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.420 + run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.421 - name: Install awf binary run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.23.0 - name: Determine automatic lockdown mode for GitHub MCP Server @@ -315,7 +315,7 @@ jobs: const determineAutomaticLockdown = require('/opt/gh-aw/actions/determine_automatic_lockdown.cjs'); await determineAutomaticLockdown(github, context, core); - name: Download container images - run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.7 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine + run: bash /opt/gh-aw/actions/download_docker_images.sh ghcr.io/github/gh-aw-firewall/agent:0.23.0 ghcr.io/github/gh-aw-firewall/api-proxy:0.23.0 ghcr.io/github/gh-aw-firewall/squid:0.23.0 ghcr.io/github/gh-aw-mcpg:v0.1.8 ghcr.io/github/github-mcp-server:v0.31.0 node:lts-alpine - name: Write Safe Outputs Config run: | mkdir -p /opt/gh-aw/safeoutputs @@ -604,7 +604,7 @@ jobs: export DEBUG="*" export GH_AW_ENGINE="copilot" - export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.7' + export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_LOCKDOWN -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.1.8' mkdir -p /home/runner/.copilot cat << GH_AW_MCP_CONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh @@ -946,6 +946,9 @@ jobs: contents: read discussions: write issues: write + concurrency: + group: "gh-aw-conclusion-constraint-solving-potd" + cancel-in-progress: false outputs: noop_message: ${{ steps.noop.outputs.noop_message }} tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} diff --git a/actions/setup-cli/install.sh b/actions/setup-cli/install.sh index 58d73c6805d..e1ac3479a12 100755 --- a/actions/setup-cli/install.sh +++ b/actions/setup-cli/install.sh @@ -239,17 +239,8 @@ fi if [ "$TRY_GH_INSTALL" = true ] && command -v gh &> /dev/null; then print_info "Attempting to install gh-aw using 'gh extension install'..." - # Call gh extension install directly to avoid command injection - install_result=0 - if [ -n "$VERSION" ] && [ "$VERSION" != "latest" ]; then - gh extension install "$REPO" --force --pin "$VERSION" 2>&1 | tee /tmp/gh-install.log - install_result=${PIPESTATUS[0]} - else - gh extension install "$REPO" --force 2>&1 | tee /tmp/gh-install.log - install_result=${PIPESTATUS[0]} - fi - - if [ $install_result -eq 0 ]; then + # Try to install using gh + if gh extension install "$REPO" --force 2>&1 | tee /tmp/gh-install.log; then # Verify the installation succeeded if gh aw version &> /dev/null; then INSTALLED_VERSION=$(gh aw version 2>&1 | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -1) @@ -258,7 +249,7 @@ if [ "$TRY_GH_INSTALL" = true ] && command -v gh &> /dev/null; then # Set output for GitHub Actions if [ -n "${GITHUB_OUTPUT}" ]; then - echo "installed_version=${INSTALLED_VERSION}" >> "${GITHUB_OUTPUT}" + echo "installed_version=${VERSION}" >> "${GITHUB_OUTPUT}" fi exit 0 From 612c7792131bf839586f8f36a091b0b757fe3ca5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 5 Mar 2026 04:00:12 +0000 Subject: [PATCH 3/3] Fix ambiguous label constraint messages by quoting labels with spaces Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/workflow/safe_outputs_tools_test.go | 26 ++++++++++++++++---- pkg/workflow/tool_description_enhancer.go | 29 ++++++++++++++++------- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/pkg/workflow/safe_outputs_tools_test.go b/pkg/workflow/safe_outputs_tools_test.go index 35e7791735d..03e66a6e40c 100644 --- a/pkg/workflow/safe_outputs_tools_test.go +++ b/pkg/workflow/safe_outputs_tools_test.go @@ -419,7 +419,7 @@ func TestEnhanceToolDescription(t *testing.T) { Labels: []string{"bug", "enhancement"}, }, }, - wantContains: []string{"CONSTRAINTS:", "Labels [bug enhancement] will be automatically added"}, + wantContains: []string{"CONSTRAINTS:", `Labels ["bug" "enhancement"] will be automatically added`}, }, { name: "create_issue with multiple constraints", @@ -437,7 +437,7 @@ func TestEnhanceToolDescription(t *testing.T) { "CONSTRAINTS:", "Maximum 3 issue(s)", `Title will be prefixed with "[bot] "`, - "Labels [automated]", + `Labels ["automated"]`, `Issues will be created in repository "owner/repo"`, }, }, @@ -454,7 +454,23 @@ func TestEnhanceToolDescription(t *testing.T) { wantContains: []string{ "CONSTRAINTS:", "Maximum 5 label(s)", - "Only these labels are allowed: [bug enhancement question]", + `Only these labels are allowed: ["bug" "enhancement" "question"]`, + }, + }, + { + name: "add_labels with spaces in label names", + toolName: "add_labels", + baseDescription: "Add labels to an issue or pull request.", + safeOutputs: &SafeOutputsConfig{ + AddLabels: &AddLabelsConfig{ + BaseSafeOutputConfig: BaseSafeOutputConfig{Max: strPtr("3")}, + Allowed: []string{"bug", "feature request", "good first issue", "help wanted"}, + }, + }, + wantContains: []string{ + "CONSTRAINTS:", + "Maximum 3 label(s)", + `Only these labels are allowed: ["bug" "feature request" "good first issue" "help wanted"]`, }, }, { @@ -698,7 +714,7 @@ func TestGenerateFilteredToolsJSONWithEnhancedDescriptions(t *testing.T) { assert.Contains(t, description, "CONSTRAINTS:", "Description should contain constraints") assert.Contains(t, description, "Maximum 5 issue(s)", "Description should include max constraint") assert.Contains(t, description, `Title will be prefixed with "[automated] "`, "Description should include title prefix") - assert.Contains(t, description, "Labels [bot enhancement]", "Description should include labels") + assert.Contains(t, description, `Labels ["bot" "enhancement"]`, "Description should include labels") // Find and verify add_labels tool has enhanced description var addLabelsTool map[string]any @@ -713,7 +729,7 @@ func TestGenerateFilteredToolsJSONWithEnhancedDescriptions(t *testing.T) { labelsDescription, ok := addLabelsTool["description"].(string) require.True(t, ok, "description should be a string") assert.Contains(t, labelsDescription, "CONSTRAINTS:", "Description should contain constraints") - assert.Contains(t, labelsDescription, "Only these labels are allowed: [bug enhancement]", "Description should include allowed labels") + assert.Contains(t, labelsDescription, `Only these labels are allowed: ["bug" "enhancement"]`, "Description should include allowed labels") } func TestRepoParameterAddedOnlyWithAllowedRepos(t *testing.T) { diff --git a/pkg/workflow/tool_description_enhancer.go b/pkg/workflow/tool_description_enhancer.go index 65d3ac6a05a..d8a14a932e5 100644 --- a/pkg/workflow/tool_description_enhancer.go +++ b/pkg/workflow/tool_description_enhancer.go @@ -9,6 +9,19 @@ import ( var toolDescriptionEnhancerLog = logger.New("workflow:tool_description_enhancer") +// formatLabelList formats a slice of labels with proper quoting for readability +// Example: ["bug", "feature request", "docs"] -> ["bug" "feature request" "docs"] +func formatLabelList(labels []string) string { + if len(labels) == 0 { + return "[]" + } + quoted := make([]string, len(labels)) + for i, label := range labels { + quoted[i] = fmt.Sprintf("%q", label) + } + return "[" + strings.Join(quoted, " ") + "]" +} + // enhanceToolDescription adds configuration-specific constraints to tool descriptions // This provides agents with context about limits and restrictions configured in the workflow func enhanceToolDescription(toolName, baseDescription string, safeOutputs *SafeOutputsConfig) string { @@ -31,13 +44,13 @@ func enhanceToolDescription(toolName, baseDescription string, safeOutputs *SafeO constraints = append(constraints, fmt.Sprintf("Title will be prefixed with %q.", config.TitlePrefix)) } if len(config.Labels) > 0 { - constraints = append(constraints, fmt.Sprintf("Labels %v will be automatically added.", config.Labels)) + constraints = append(constraints, fmt.Sprintf("Labels %s will be automatically added.", formatLabelList(config.Labels))) } if len(config.AllowedLabels) > 0 { - constraints = append(constraints, fmt.Sprintf("Only these labels are allowed: %v.", config.AllowedLabels)) + constraints = append(constraints, fmt.Sprintf("Only these labels are allowed: %s.", formatLabelList(config.AllowedLabels))) } if len(config.Assignees) > 0 { - constraints = append(constraints, fmt.Sprintf("Assignees %v will be automatically assigned.", config.Assignees)) + constraints = append(constraints, fmt.Sprintf("Assignees %s will be automatically assigned.", formatLabelList(config.Assignees))) } if config.TargetRepoSlug != "" { constraints = append(constraints, fmt.Sprintf("Issues will be created in repository %q.", config.TargetRepoSlug)) @@ -72,7 +85,7 @@ func enhanceToolDescription(toolName, baseDescription string, safeOutputs *SafeO constraints = append(constraints, fmt.Sprintf("Discussions will be created in category %q.", config.Category)) } if len(config.AllowedLabels) > 0 { - constraints = append(constraints, fmt.Sprintf("Only these labels are allowed: %v.", config.AllowedLabels)) + constraints = append(constraints, fmt.Sprintf("Only these labels are allowed: %s.", formatLabelList(config.AllowedLabels))) } if config.TargetRepoSlug != "" { constraints = append(constraints, fmt.Sprintf("Discussions will be created in repository %q.", config.TargetRepoSlug)) @@ -144,16 +157,16 @@ func enhanceToolDescription(toolName, baseDescription string, safeOutputs *SafeO constraints = append(constraints, fmt.Sprintf("Title will be prefixed with %q.", config.TitlePrefix)) } if len(config.Labels) > 0 { - constraints = append(constraints, fmt.Sprintf("Labels %v will be automatically added.", config.Labels)) + constraints = append(constraints, fmt.Sprintf("Labels %s will be automatically added.", formatLabelList(config.Labels))) } if len(config.AllowedLabels) > 0 { - constraints = append(constraints, fmt.Sprintf("Only these labels are allowed: %v.", config.AllowedLabels)) + constraints = append(constraints, fmt.Sprintf("Only these labels are allowed: %s.", formatLabelList(config.AllowedLabels))) } if config.Draft != nil && *config.Draft == "true" { constraints = append(constraints, "PRs will be created as drafts.") } if len(config.Reviewers) > 0 { - constraints = append(constraints, fmt.Sprintf("Reviewers %v will be assigned.", config.Reviewers)) + constraints = append(constraints, fmt.Sprintf("Reviewers %s will be assigned.", formatLabelList(config.Reviewers))) } } @@ -201,7 +214,7 @@ func enhanceToolDescription(toolName, baseDescription string, safeOutputs *SafeO constraints = append(constraints, fmt.Sprintf("Maximum %d label(s) can be added.", templatableIntValue(config.Max))) } if len(config.Allowed) > 0 { - constraints = append(constraints, fmt.Sprintf("Only these labels are allowed: %v.", config.Allowed)) + constraints = append(constraints, fmt.Sprintf("Only these labels are allowed: %s.", formatLabelList(config.Allowed))) } if config.Target != "" { constraints = append(constraints, fmt.Sprintf("Target: %s.", config.Target))