diff --git a/.github/workflows/security-alert-burndown.lock.yml b/.github/workflows/security-alert-burndown.lock.yml index 2ea7bc9196..de75327f7b 100644 --- a/.github/workflows/security-alert-burndown.lock.yml +++ b/.github/workflows/security-alert-burndown.lock.yml @@ -556,7 +556,7 @@ jobs: "maxLength": 128 }, "content_number": { - "issueNumberOrTemporaryId": true + "optionalPositiveInteger": true }, "content_type": { "type": "string", @@ -2183,32 +2183,32 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" - - name: Process Safe Outputs - id: process_safe_outputs + - name: Process Project-Related Safe Outputs + id: process_project_safe_outputs uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"assignees\":[\"copilot\"],\"max\":1},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1}}" + GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG: "{\"create_project_status_update\":{\"max\":1},\"update_project\":{\"max\":100}}" + GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} with: - github-token: ${{ secrets.GH_AW_AGENT_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} + github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} script: | const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/safe_output_handler_manager.cjs'); + const { main } = require('/opt/gh-aw/actions/safe_output_project_handler_manager.cjs'); await main(); - - name: Process Project-Related Safe Outputs - id: process_project_safe_outputs + - name: Process Safe Outputs + id: process_safe_outputs uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_TEMPORARY_ID_MAP: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} - GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG: "{\"create_project_status_update\":{\"max\":1},\"update_project\":{\"max\":100}}" - GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} + GH_AW_TEMPORARY_PROJECT_MAP: ${{ steps.process_project_safe_outputs.outputs.temporary_project_map }} + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"assignees\":[\"copilot\"],\"max\":1},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1}}" with: - github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} + github-token: ${{ secrets.GH_AW_AGENT_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/safe_output_project_handler_manager.cjs'); + const { main } = require('/opt/gh-aw/actions/safe_output_handler_manager.cjs'); await main(); diff --git a/actions/setup/js/create_issue.cjs b/actions/setup/js/create_issue.cjs index b55e7bcbd9..5c82a4ea2e 100644 --- a/actions/setup/js/create_issue.cjs +++ b/actions/setup/js/create_issue.cjs @@ -1,6 +1,30 @@ // @ts-check /// +/** + * Module-level storage for issues that need copilot assignment + * This is populated by the create_issue handler when GH_AW_ASSIGN_COPILOT is true + * and consumed by the handler manager to set the issues_to_assign_copilot output + * @type {Array} + */ +let issuesToAssignCopilotGlobal = []; + +/** + * Get the list of issues that need copilot assignment + * @returns {Array} Array of "repo:number" strings + */ +function getIssuesToAssignCopilot() { + return issuesToAssignCopilotGlobal; +} + +/** + * Reset the list of issues that need copilot assignment + * Used for testing + */ +function resetIssuesToAssignCopilot() { + issuesToAssignCopilotGlobal = []; +} + const { sanitizeLabelContent } = require("./sanitize_label_content.cjs"); const { generateFooter, generateWorkflowIdMarker } = require("./generate_footer.cjs"); const { getTrackerID } = require("./get_tracker_id.cjs"); @@ -174,6 +198,9 @@ async function main(config = {}) { const groupEnabled = config.group === true || config.group === "true"; const closeOlderIssuesEnabled = config.close_older_issues === true || config.close_older_issues === "true"; + // Check if copilot assignment is enabled + const assignCopilot = process.env.GH_AW_ASSIGN_COPILOT === "true"; + core.info(`Default target repo: ${defaultTargetRepo}`); if (allowedRepos.size > 0) { core.info(`Allowed repos: ${Array.from(allowedRepos).join(", ")}`); @@ -347,6 +374,13 @@ async function main(config = {}) { .filter(assignee => assignee) .filter((assignee, index, arr) => arr.indexOf(assignee) === index); + // Check if copilot is in the assignees list + const hasCopilot = assignees.includes("copilot"); + + // Filter out "copilot" from assignees - it will be assigned separately using GraphQL + // Copilot is not a valid GitHub user and must be assigned via the agent assignment API + assignees = assignees.filter(assignee => assignee !== "copilot"); + let title = createIssueItem.title ? createIssueItem.title.trim() : ""; // Replace temporary ID references in the body using already-created issues @@ -428,6 +462,12 @@ async function main(config = {}) { temporaryIdMap.set(normalizeTemporaryId(temporaryId), { repo: qualifiedItemRepo, number: issue.number }); core.info(`Stored temporary ID mapping: ${temporaryId} -> ${qualifiedItemRepo}#${issue.number}`); + // Track issue for copilot assignment if needed + if (hasCopilot && assignCopilot) { + issuesToAssignCopilotGlobal.push(`${qualifiedItemRepo}:${issue.number}`); + core.info(`Queued issue ${qualifiedItemRepo}#${issue.number} for copilot assignment`); + } + // Close older issues if enabled if (closeOlderIssuesEnabled) { if (workflowId) { @@ -591,4 +631,4 @@ async function main(config = {}) { }; } -module.exports = { main, createParentIssueTemplate, searchForExistingParent, getSubIssueCount }; +module.exports = { main, createParentIssueTemplate, searchForExistingParent, getSubIssueCount, getIssuesToAssignCopilot, resetIssuesToAssignCopilot }; diff --git a/actions/setup/js/safe_output_handler_manager.cjs b/actions/setup/js/safe_output_handler_manager.cjs index ce9176c1e1..38dbed8f17 100644 --- a/actions/setup/js/safe_output_handler_manager.cjs +++ b/actions/setup/js/safe_output_handler_manager.cjs @@ -15,6 +15,7 @@ const { hasUnresolvedTemporaryIds, replaceTemporaryIdReferences, normalizeTempor const { generateMissingInfoSections } = require("./missing_info_formatter.cjs"); const { setCollectedMissings } = require("./missing_messages_helper.cjs"); const { writeSafeOutputSummaries } = require("./safe_output_summary.cjs"); +const { getIssuesToAssignCopilot } = require("./create_issue.cjs"); const DEFAULT_AGENTIC_CAMPAIGN_LABEL = "agentic-campaign"; @@ -793,6 +794,11 @@ async function main() { try { core.info("Safe Output Handler Manager starting..."); + // Reset create_issue handler's global state to ensure clean state for this run + // This prevents stale data accumulation if the module is reused + const { resetIssuesToAssignCopilot } = require("./create_issue.cjs"); + resetIssuesToAssignCopilot(); + // Load configuration const config = loadConfig(); core.debug(`Configuration: ${JSON.stringify(Object.keys(config))}`); @@ -885,6 +891,16 @@ async function main() { // Export processed count for consistency with project handler core.setOutput("processed_count", successCount); + // Export issues that need copilot assignment (if any) + const issuesToAssignCopilot = getIssuesToAssignCopilot(); + if (issuesToAssignCopilot.length > 0) { + const issuesToAssignStr = issuesToAssignCopilot.join(","); + core.setOutput("issues_to_assign_copilot", issuesToAssignStr); + core.info(`Exported ${issuesToAssignCopilot.length} issue(s) for copilot assignment: ${issuesToAssignStr}`); + } else { + core.setOutput("issues_to_assign_copilot", ""); + } + core.info("Safe Output Handler Manager completed"); } catch (error) { core.setFailed(`Handler manager failed: ${getErrorMessage(error)}`);