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)}`);