diff --git a/.github/workflows/smoke-copilot-aoai-apikey.lock.yml b/.github/workflows/smoke-copilot-aoai-apikey.lock.yml index 6d6681fbeac..a607ac3204e 100644 --- a/.github/workflows/smoke-copilot-aoai-apikey.lock.yml +++ b/.github/workflows/smoke-copilot-aoai-apikey.lock.yml @@ -784,9 +784,9 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs/upload-artifacts" - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_4b3ad3e07e15ba26_EOF' - {"add_comment":{"allowed_repos":["github/gh-aw"],"hide_older_comments":true,"max":2},"add_labels":{"allowed":["smoke-copilot-aoai-apikey"],"allowed_repos":["github/gh-aw"]},"comment_memory":{"max":1,"memory_id":"default"},"create_check_run":{"max":1,"name":"Smoke Copilot - AOAI (apikey)"},"create_discussion":{"category":"announcements","close_older_discussions":true,"close_older_key":"smoke-copilot-aoai-apikey","expires":2,"fallback_to_issue":true,"labels":["ai-generated"],"max":1},"create_issue":{"close_older_issues":true,"close_older_key":"smoke-copilot-aoai-apikey","expires":2,"group":true,"labels":["automation","testing"],"max":1},"create_pull_request_review_comment":{"max":5,"side":"RIGHT"},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"workflow_files":{"haiku-printer":".yml"},"workflows":["haiku-printer"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"remove_labels":{"allowed":["smoke"]},"reply_to_pull_request_review_comment":{"max":5},"report_incomplete":{},"send-slack-message":{"description":"Send a message to Slack (stub for testing)","inputs":{"message":{"description":"The message to send","required":false,"type":"string"}},"output":"Slack message stub executed!"},"set_issue_type":{},"submit_pull_request_review":{"max":1},"upload_artifact":{"max-size-bytes":104857600,"max-uploads":1,"retention-days":1,"skip-archive":true}} - GH_AW_SAFE_OUTPUTS_CONFIG_4b3ad3e07e15ba26_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_703092194a588eb7_EOF' + {"add_comment":{"allowed_repos":["github/gh-aw"],"hide_older_comments":true,"max":2},"add_labels":{"allowed":["smoke-copilot-aoai-apikey"],"allowed_repos":["github/gh-aw"]},"comment_memory":{"max":1,"memory_id":"default"},"create_check_run":{"max":1,"name":"Smoke Copilot - AOAI (apikey)"},"create_discussion":{"category":"announcements","close_older_discussions":true,"close_older_key":"smoke-copilot-aoai-apikey","expires":2,"fallback_to_issue":true,"labels":["ai-generated"],"max":1},"create_issue":{"close_older_issues":true,"close_older_key":"smoke-copilot-aoai-apikey","expires":2,"group":true,"labels":["automation","testing"],"max":1},"create_pull_request_review_comment":{"max":5,"side":"RIGHT"},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"required_inputs":{"haiku-printer":["message"]},"workflow_files":{"haiku-printer":".yml"},"workflows":["haiku-printer"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"remove_labels":{"allowed":["smoke"]},"reply_to_pull_request_review_comment":{"max":5},"report_incomplete":{},"send-slack-message":{"description":"Send a message to Slack (stub for testing)","inputs":{"message":{"description":"The message to send","required":false,"type":"string"}},"output":"Slack message stub executed!"},"set_issue_type":{},"submit_pull_request_review":{"max":1},"upload_artifact":{"max-size-bytes":104857600,"max-uploads":1,"retention-days":1,"skip-archive":true}} + GH_AW_SAFE_OUTPUTS_CONFIG_703092194a588eb7_EOF - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -2926,7 +2926,7 @@ jobs: GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} GH_AW_SAFE_OUTPUT_JOBS: "{\"send_slack_message\":\"\"}" - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"allowed_repos\":[\"github/gh-aw\"],\"hide_older_comments\":true,\"max\":2},\"add_labels\":{\"allowed\":[\"smoke-copilot-aoai-apikey\"],\"allowed_repos\":[\"github/gh-aw\"]},\"comment_memory\":{\"max\":1,\"memory_id\":\"default\"},\"create_check_run\":{\"max\":1,\"name\":\"Smoke Copilot - AOAI (apikey)\"},\"create_discussion\":{\"category\":\"announcements\",\"close_older_discussions\":true,\"close_older_key\":\"smoke-copilot-aoai-apikey\",\"expires\":2,\"fallback_to_issue\":true,\"labels\":[\"ai-generated\"],\"max\":1},\"create_issue\":{\"close_older_issues\":true,\"close_older_key\":\"smoke-copilot-aoai-apikey\",\"expires\":2,\"group\":true,\"labels\":[\"automation\",\"testing\"],\"max\":1},\"create_pull_request_review_comment\":{\"max\":5,\"side\":\"RIGHT\"},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"workflow_files\":{\"haiku-printer\":\".yml\"},\"workflows\":[\"haiku-printer\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"remove_labels\":{\"allowed\":[\"smoke\"]},\"reply_to_pull_request_review_comment\":{\"max\":5},\"report_incomplete\":{},\"set_issue_type\":{},\"submit_pull_request_review\":{\"max\":1},\"upload_artifact\":{\"max-size-bytes\":104857600,\"max-uploads\":1,\"retention-days\":1,\"skip-archive\":true}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"allowed_repos\":[\"github/gh-aw\"],\"hide_older_comments\":true,\"max\":2},\"add_labels\":{\"allowed\":[\"smoke-copilot-aoai-apikey\"],\"allowed_repos\":[\"github/gh-aw\"]},\"comment_memory\":{\"max\":1,\"memory_id\":\"default\"},\"create_check_run\":{\"max\":1,\"name\":\"Smoke Copilot - AOAI (apikey)\"},\"create_discussion\":{\"category\":\"announcements\",\"close_older_discussions\":true,\"close_older_key\":\"smoke-copilot-aoai-apikey\",\"expires\":2,\"fallback_to_issue\":true,\"labels\":[\"ai-generated\"],\"max\":1},\"create_issue\":{\"close_older_issues\":true,\"close_older_key\":\"smoke-copilot-aoai-apikey\",\"expires\":2,\"group\":true,\"labels\":[\"automation\",\"testing\"],\"max\":1},\"create_pull_request_review_comment\":{\"max\":5,\"side\":\"RIGHT\"},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"required_inputs\":{\"haiku-printer\":[\"message\"]},\"workflow_files\":{\"haiku-printer\":\".yml\"},\"workflows\":[\"haiku-printer\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"remove_labels\":{\"allowed\":[\"smoke\"]},\"reply_to_pull_request_review_comment\":{\"max\":5},\"report_incomplete\":{},\"set_issue_type\":{},\"submit_pull_request_review\":{\"max\":1},\"upload_artifact\":{\"max-size-bytes\":104857600,\"max-uploads\":1,\"retention-days\":1,\"skip-archive\":true}}" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/smoke-copilot-aoai-entra.lock.yml b/.github/workflows/smoke-copilot-aoai-entra.lock.yml index c4a23dc890b..c730c224b33 100644 --- a/.github/workflows/smoke-copilot-aoai-entra.lock.yml +++ b/.github/workflows/smoke-copilot-aoai-entra.lock.yml @@ -785,9 +785,9 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs/upload-artifacts" - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_b03c54a991979970_EOF' - {"add_comment":{"allowed_repos":["github/gh-aw"],"hide_older_comments":true,"max":2},"add_labels":{"allowed":["smoke-copilot-aoai-entra"],"allowed_repos":["github/gh-aw"]},"comment_memory":{"max":1,"memory_id":"default"},"create_check_run":{"max":1,"name":"Smoke Copilot - AOAI (Entra)"},"create_discussion":{"category":"announcements","close_older_discussions":true,"close_older_key":"smoke-copilot-aoai-entra","expires":2,"fallback_to_issue":true,"labels":["ai-generated"],"max":1},"create_issue":{"close_older_issues":true,"close_older_key":"smoke-copilot-aoai-entra","expires":2,"group":true,"labels":["automation","testing"],"max":1},"create_pull_request_review_comment":{"max":5,"side":"RIGHT"},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"workflow_files":{"haiku-printer":".yml"},"workflows":["haiku-printer"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"remove_labels":{"allowed":["smoke"]},"reply_to_pull_request_review_comment":{"max":5},"report_incomplete":{},"send-slack-message":{"description":"Send a message to Slack (stub for testing)","inputs":{"message":{"description":"The message to send","required":false,"type":"string"}},"output":"Slack message stub executed!"},"set_issue_type":{},"submit_pull_request_review":{"max":1},"upload_artifact":{"max-size-bytes":104857600,"max-uploads":1,"retention-days":1,"skip-archive":true}} - GH_AW_SAFE_OUTPUTS_CONFIG_b03c54a991979970_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_b8d26c06196eb8c1_EOF' + {"add_comment":{"allowed_repos":["github/gh-aw"],"hide_older_comments":true,"max":2},"add_labels":{"allowed":["smoke-copilot-aoai-entra"],"allowed_repos":["github/gh-aw"]},"comment_memory":{"max":1,"memory_id":"default"},"create_check_run":{"max":1,"name":"Smoke Copilot - AOAI (Entra)"},"create_discussion":{"category":"announcements","close_older_discussions":true,"close_older_key":"smoke-copilot-aoai-entra","expires":2,"fallback_to_issue":true,"labels":["ai-generated"],"max":1},"create_issue":{"close_older_issues":true,"close_older_key":"smoke-copilot-aoai-entra","expires":2,"group":true,"labels":["automation","testing"],"max":1},"create_pull_request_review_comment":{"max":5,"side":"RIGHT"},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"required_inputs":{"haiku-printer":["message"]},"workflow_files":{"haiku-printer":".yml"},"workflows":["haiku-printer"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"remove_labels":{"allowed":["smoke"]},"reply_to_pull_request_review_comment":{"max":5},"report_incomplete":{},"send-slack-message":{"description":"Send a message to Slack (stub for testing)","inputs":{"message":{"description":"The message to send","required":false,"type":"string"}},"output":"Slack message stub executed!"},"set_issue_type":{},"submit_pull_request_review":{"max":1},"upload_artifact":{"max-size-bytes":104857600,"max-uploads":1,"retention-days":1,"skip-archive":true}} + GH_AW_SAFE_OUTPUTS_CONFIG_b8d26c06196eb8c1_EOF - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -2937,7 +2937,7 @@ jobs: GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} GH_AW_SAFE_OUTPUT_JOBS: "{\"send_slack_message\":\"\"}" - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"allowed_repos\":[\"github/gh-aw\"],\"hide_older_comments\":true,\"max\":2},\"add_labels\":{\"allowed\":[\"smoke-copilot-aoai-entra\"],\"allowed_repos\":[\"github/gh-aw\"]},\"comment_memory\":{\"max\":1,\"memory_id\":\"default\"},\"create_check_run\":{\"max\":1,\"name\":\"Smoke Copilot - AOAI (Entra)\"},\"create_discussion\":{\"category\":\"announcements\",\"close_older_discussions\":true,\"close_older_key\":\"smoke-copilot-aoai-entra\",\"expires\":2,\"fallback_to_issue\":true,\"labels\":[\"ai-generated\"],\"max\":1},\"create_issue\":{\"close_older_issues\":true,\"close_older_key\":\"smoke-copilot-aoai-entra\",\"expires\":2,\"group\":true,\"labels\":[\"automation\",\"testing\"],\"max\":1},\"create_pull_request_review_comment\":{\"max\":5,\"side\":\"RIGHT\"},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"workflow_files\":{\"haiku-printer\":\".yml\"},\"workflows\":[\"haiku-printer\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"remove_labels\":{\"allowed\":[\"smoke\"]},\"reply_to_pull_request_review_comment\":{\"max\":5},\"report_incomplete\":{},\"set_issue_type\":{},\"submit_pull_request_review\":{\"max\":1},\"upload_artifact\":{\"max-size-bytes\":104857600,\"max-uploads\":1,\"retention-days\":1,\"skip-archive\":true}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"allowed_repos\":[\"github/gh-aw\"],\"hide_older_comments\":true,\"max\":2},\"add_labels\":{\"allowed\":[\"smoke-copilot-aoai-entra\"],\"allowed_repos\":[\"github/gh-aw\"]},\"comment_memory\":{\"max\":1,\"memory_id\":\"default\"},\"create_check_run\":{\"max\":1,\"name\":\"Smoke Copilot - AOAI (Entra)\"},\"create_discussion\":{\"category\":\"announcements\",\"close_older_discussions\":true,\"close_older_key\":\"smoke-copilot-aoai-entra\",\"expires\":2,\"fallback_to_issue\":true,\"labels\":[\"ai-generated\"],\"max\":1},\"create_issue\":{\"close_older_issues\":true,\"close_older_key\":\"smoke-copilot-aoai-entra\",\"expires\":2,\"group\":true,\"labels\":[\"automation\",\"testing\"],\"max\":1},\"create_pull_request_review_comment\":{\"max\":5,\"side\":\"RIGHT\"},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"required_inputs\":{\"haiku-printer\":[\"message\"]},\"workflow_files\":{\"haiku-printer\":\".yml\"},\"workflows\":[\"haiku-printer\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"remove_labels\":{\"allowed\":[\"smoke\"]},\"reply_to_pull_request_review_comment\":{\"max\":5},\"report_incomplete\":{},\"set_issue_type\":{},\"submit_pull_request_review\":{\"max\":1},\"upload_artifact\":{\"max-size-bytes\":104857600,\"max-uploads\":1,\"retention-days\":1,\"skip-archive\":true}}" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/smoke-copilot-arm.lock.yml b/.github/workflows/smoke-copilot-arm.lock.yml index 9c264358e48..106c70c0ba1 100644 --- a/.github/workflows/smoke-copilot-arm.lock.yml +++ b/.github/workflows/smoke-copilot-arm.lock.yml @@ -720,9 +720,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_503fc9cb30bfba80_EOF' - {"add_comment":{"allowed_repos":["github/gh-aw"],"hide_older_comments":true,"max":2},"add_labels":{"allowed":["smoke-copilot-arm"],"allowed_repos":["github/gh-aw"]},"create_discussion":{"category":"announcements","close_older_discussions":true,"expires":2,"fallback_to_issue":true,"labels":["ai-generated"],"max":1},"create_issue":{"close_older_issues":true,"close_older_key":"smoke-copilot-arm","expires":2,"group":true,"labels":["automation","testing"],"max":1},"create_pull_request_review_comment":{"max":5,"side":"RIGHT"},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"workflow_files":{"haiku-printer":".yml"},"workflows":["haiku-printer"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"remove_labels":{"allowed":["smoke"]},"report_incomplete":{},"send-slack-message":{"description":"Send a message to Slack (stub for testing)","inputs":{"message":{"description":"The message to send","required":false,"type":"string"}},"output":"Slack message stub executed!"},"submit_pull_request_review":{"max":1}} - GH_AW_SAFE_OUTPUTS_CONFIG_503fc9cb30bfba80_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_912bc2a744b8eb7b_EOF' + {"add_comment":{"allowed_repos":["github/gh-aw"],"hide_older_comments":true,"max":2},"add_labels":{"allowed":["smoke-copilot-arm"],"allowed_repos":["github/gh-aw"]},"create_discussion":{"category":"announcements","close_older_discussions":true,"expires":2,"fallback_to_issue":true,"labels":["ai-generated"],"max":1},"create_issue":{"close_older_issues":true,"close_older_key":"smoke-copilot-arm","expires":2,"group":true,"labels":["automation","testing"],"max":1},"create_pull_request_review_comment":{"max":5,"side":"RIGHT"},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"required_inputs":{"haiku-printer":["message"]},"workflow_files":{"haiku-printer":".yml"},"workflows":["haiku-printer"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"remove_labels":{"allowed":["smoke"]},"report_incomplete":{},"send-slack-message":{"description":"Send a message to Slack (stub for testing)","inputs":{"message":{"description":"The message to send","required":false,"type":"string"}},"output":"Slack message stub executed!"},"submit_pull_request_review":{"max":1}} + GH_AW_SAFE_OUTPUTS_CONFIG_912bc2a744b8eb7b_EOF - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -2677,7 +2677,7 @@ jobs: GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} GH_AW_SAFE_OUTPUT_JOBS: "{\"send_slack_message\":\"\"}" - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"allowed_repos\":[\"github/gh-aw\"],\"hide_older_comments\":true,\"max\":2},\"add_labels\":{\"allowed\":[\"smoke-copilot-arm\"],\"allowed_repos\":[\"github/gh-aw\"]},\"create_discussion\":{\"category\":\"announcements\",\"close_older_discussions\":true,\"expires\":2,\"fallback_to_issue\":true,\"labels\":[\"ai-generated\"],\"max\":1},\"create_issue\":{\"close_older_issues\":true,\"close_older_key\":\"smoke-copilot-arm\",\"expires\":2,\"group\":true,\"labels\":[\"automation\",\"testing\"],\"max\":1},\"create_pull_request_review_comment\":{\"max\":5,\"side\":\"RIGHT\"},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"workflow_files\":{\"haiku-printer\":\".yml\"},\"workflows\":[\"haiku-printer\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"remove_labels\":{\"allowed\":[\"smoke\"]},\"report_incomplete\":{},\"submit_pull_request_review\":{\"max\":1}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"allowed_repos\":[\"github/gh-aw\"],\"hide_older_comments\":true,\"max\":2},\"add_labels\":{\"allowed\":[\"smoke-copilot-arm\"],\"allowed_repos\":[\"github/gh-aw\"]},\"create_discussion\":{\"category\":\"announcements\",\"close_older_discussions\":true,\"expires\":2,\"fallback_to_issue\":true,\"labels\":[\"ai-generated\"],\"max\":1},\"create_issue\":{\"close_older_issues\":true,\"close_older_key\":\"smoke-copilot-arm\",\"expires\":2,\"group\":true,\"labels\":[\"automation\",\"testing\"],\"max\":1},\"create_pull_request_review_comment\":{\"max\":5,\"side\":\"RIGHT\"},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"required_inputs\":{\"haiku-printer\":[\"message\"]},\"workflow_files\":{\"haiku-printer\":\".yml\"},\"workflows\":[\"haiku-printer\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"remove_labels\":{\"allowed\":[\"smoke\"]},\"report_incomplete\":{},\"submit_pull_request_review\":{\"max\":1}}" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index 8d67cf4ecc5..d106cc931e6 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -800,9 +800,9 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs/upload-artifacts" - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_d27a3a20e778c2d0_EOF' - {"add_comment":{"allowed_repos":["github/gh-aw"],"hide_older_comments":true,"max":2},"add_labels":{"allowed":["smoke-copilot"],"allowed_repos":["github/gh-aw"]},"comment_memory":{"max":1,"memory_id":"default"},"create_check_run":{"max":1,"name":"Smoke Copilot"},"create_discussion":{"category":"announcements","close_older_discussions":true,"close_older_key":"smoke-copilot","expires":2,"fallback_to_issue":true,"labels":["ai-generated"],"max":1},"create_issue":{"close_older_issues":true,"close_older_key":"smoke-copilot","expires":2,"group":true,"labels":["automation","testing"],"max":1},"create_pull_request_review_comment":{"max":5,"side":"RIGHT"},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"workflow_files":{"haiku-printer":".yml"},"workflows":["haiku-printer"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"remove_labels":{"allowed":["smoke"]},"reply_to_pull_request_review_comment":{"max":5},"report_incomplete":{},"send-slack-message":{"description":"Send a message to Slack (stub for testing)","inputs":{"message":{"description":"The message to send","required":false,"type":"string"}},"output":"Slack message stub executed!"},"set_issue_type":{},"submit_pull_request_review":{"max":1},"upload_artifact":{"max-size-bytes":104857600,"max-uploads":1,"retention-days":1,"skip-archive":true}} - GH_AW_SAFE_OUTPUTS_CONFIG_d27a3a20e778c2d0_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_17324aeed6eb2961_EOF' + {"add_comment":{"allowed_repos":["github/gh-aw"],"hide_older_comments":true,"max":2},"add_labels":{"allowed":["smoke-copilot"],"allowed_repos":["github/gh-aw"]},"comment_memory":{"max":1,"memory_id":"default"},"create_check_run":{"max":1,"name":"Smoke Copilot"},"create_discussion":{"category":"announcements","close_older_discussions":true,"close_older_key":"smoke-copilot","expires":2,"fallback_to_issue":true,"labels":["ai-generated"],"max":1},"create_issue":{"close_older_issues":true,"close_older_key":"smoke-copilot","expires":2,"group":true,"labels":["automation","testing"],"max":1},"create_pull_request_review_comment":{"max":5,"side":"RIGHT"},"create_report_incomplete_issue":{},"dispatch_workflow":{"max":1,"required_inputs":{"haiku-printer":["message"]},"workflow_files":{"haiku-printer":".yml"},"workflows":["haiku-printer"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"remove_labels":{"allowed":["smoke"]},"reply_to_pull_request_review_comment":{"max":5},"report_incomplete":{},"send-slack-message":{"description":"Send a message to Slack (stub for testing)","inputs":{"message":{"description":"The message to send","required":false,"type":"string"}},"output":"Slack message stub executed!"},"set_issue_type":{},"submit_pull_request_review":{"max":1},"upload_artifact":{"max-size-bytes":104857600,"max-uploads":1,"retention-days":1,"skip-archive":true}} + GH_AW_SAFE_OUTPUTS_CONFIG_17324aeed6eb2961_EOF - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -2938,7 +2938,7 @@ jobs: GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} GH_AW_SAFE_OUTPUT_JOBS: "{\"send_slack_message\":\"\"}" - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"allowed_repos\":[\"github/gh-aw\"],\"hide_older_comments\":true,\"max\":2},\"add_labels\":{\"allowed\":[\"smoke-copilot\"],\"allowed_repos\":[\"github/gh-aw\"]},\"comment_memory\":{\"max\":1,\"memory_id\":\"default\"},\"create_check_run\":{\"max\":1,\"name\":\"Smoke Copilot\"},\"create_discussion\":{\"category\":\"announcements\",\"close_older_discussions\":true,\"close_older_key\":\"smoke-copilot\",\"expires\":2,\"fallback_to_issue\":true,\"labels\":[\"ai-generated\"],\"max\":1},\"create_issue\":{\"close_older_issues\":true,\"close_older_key\":\"smoke-copilot\",\"expires\":2,\"group\":true,\"labels\":[\"automation\",\"testing\"],\"max\":1},\"create_pull_request_review_comment\":{\"max\":5,\"side\":\"RIGHT\"},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"workflow_files\":{\"haiku-printer\":\".yml\"},\"workflows\":[\"haiku-printer\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"remove_labels\":{\"allowed\":[\"smoke\"]},\"reply_to_pull_request_review_comment\":{\"max\":5},\"report_incomplete\":{},\"set_issue_type\":{},\"submit_pull_request_review\":{\"max\":1},\"upload_artifact\":{\"max-size-bytes\":104857600,\"max-uploads\":1,\"retention-days\":1,\"skip-archive\":true}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"allowed_repos\":[\"github/gh-aw\"],\"hide_older_comments\":true,\"max\":2},\"add_labels\":{\"allowed\":[\"smoke-copilot\"],\"allowed_repos\":[\"github/gh-aw\"]},\"comment_memory\":{\"max\":1,\"memory_id\":\"default\"},\"create_check_run\":{\"max\":1,\"name\":\"Smoke Copilot\"},\"create_discussion\":{\"category\":\"announcements\",\"close_older_discussions\":true,\"close_older_key\":\"smoke-copilot\",\"expires\":2,\"fallback_to_issue\":true,\"labels\":[\"ai-generated\"],\"max\":1},\"create_issue\":{\"close_older_issues\":true,\"close_older_key\":\"smoke-copilot\",\"expires\":2,\"group\":true,\"labels\":[\"automation\",\"testing\"],\"max\":1},\"create_pull_request_review_comment\":{\"max\":5,\"side\":\"RIGHT\"},\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"max\":1,\"required_inputs\":{\"haiku-printer\":[\"message\"]},\"workflow_files\":{\"haiku-printer\":\".yml\"},\"workflows\":[\"haiku-printer\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"remove_labels\":{\"allowed\":[\"smoke\"]},\"reply_to_pull_request_review_comment\":{\"max\":5},\"report_incomplete\":{},\"set_issue_type\":{},\"submit_pull_request_review\":{\"max\":1},\"upload_artifact\":{\"max-size-bytes\":104857600,\"max-uploads\":1,\"retention-days\":1,\"skip-archive\":true}}" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/test-dispatcher.lock.yml b/.github/workflows/test-dispatcher.lock.yml index 4393484f171..65b75902efe 100644 --- a/.github/workflows/test-dispatcher.lock.yml +++ b/.github/workflows/test-dispatcher.lock.yml @@ -520,9 +520,9 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_c3c37646c1200c03_EOF' - {"create_report_incomplete_issue":{},"dispatch_workflow":{"aw_context_workflows":["test-workflow"],"max":1,"workflow_files":{"test-workflow":".lock.yml"},"workflows":["test-workflow"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_c3c37646c1200c03_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_0515e86d270c6420_EOF' + {"create_report_incomplete_issue":{},"dispatch_workflow":{"aw_context_workflows":["test-workflow"],"max":1,"required_inputs":{"test-workflow":["test_param"]},"workflow_files":{"test-workflow":".lock.yml"},"workflows":["test-workflow"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} + GH_AW_SAFE_OUTPUTS_CONFIG_0515e86d270c6420_EOF - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -1579,7 +1579,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.grafana.net,*.sentry.io,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"aw_context_workflows\":[\"test-workflow\"],\"max\":1,\"workflow_files\":{\"test-workflow\":\".lock.yml\"},\"workflows\":[\"test-workflow\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_report_incomplete_issue\":{},\"dispatch_workflow\":{\"aw_context_workflows\":[\"test-workflow\"],\"max\":1,\"required_inputs\":{\"test-workflow\":[\"test_param\"]},\"workflow_files\":{\"test-workflow\":\".lock.yml\"},\"workflows\":[\"test-workflow\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | diff --git a/actions/setup/js/dispatch_workflow.cjs b/actions/setup/js/dispatch_workflow.cjs index de8e490bb8d..4df28c29e5f 100644 --- a/actions/setup/js/dispatch_workflow.cjs +++ b/actions/setup/js/dispatch_workflow.cjs @@ -26,6 +26,7 @@ async function main(config = {}) { const allowedWorkflows = config.workflows || []; const maxCount = config.max || 1; const workflowFiles = config.workflow_files || {}; // Map of workflow name to file extension + const requiredInputsByWorkflow = config.required_inputs || {}; // Map of workflow name to required workflow_dispatch input names const awContextWorkflows = new Set(config.aw_context_workflows || []); // Workflows that accept aw_context input const githubClient = await createAuthenticatedGitHubClient(config); const { defaultTargetRepo, allowedRepos } = resolveTargetRepoConfig(config); @@ -228,6 +229,16 @@ async function main(config = {}) { inputs["aw_context"] = JSON.stringify(buildAwContext()); } + const requiredInputs = Array.isArray(requiredInputsByWorkflow[workflowName]) ? requiredInputsByWorkflow[workflowName] : []; + const missingRequiredInput = requiredInputs.find(inputName => !Object.prototype.hasOwnProperty.call(inputs, inputName)); + if (missingRequiredInput) { + return { + success: false, + reportOnly: true, + error: `Validation failed for dispatch_workflow "${workflowName}": missing required input "${missingRequiredInput}". Include it under inputs.${missingRequiredInput}.`, + }; + } + // Get the workflow file extension from compile-time resolution let extension = workflowFiles[workflowName]; if (!extension && isCrossRepoDispatch) { @@ -287,6 +298,16 @@ async function main(config = {}) { ref: ref, inputs: inputs, }); + } else if (isValidationStatus) { + const missingInputMatch = /Required input '([^']+)' not provided/i.exec(dispatchErrMessage); + if (missingInputMatch && missingInputMatch[1]) { + return { + success: false, + reportOnly: true, + error: `Validation failed for dispatch_workflow "${workflowName}": missing required input "${missingInputMatch[1]}". Include it under inputs.${missingInputMatch[1]}.`, + }; + } + throw err; } else { throw err; } diff --git a/actions/setup/js/dispatch_workflow.test.cjs b/actions/setup/js/dispatch_workflow.test.cjs index 8bdd7b2d60a..64396d9d82f 100644 --- a/actions/setup/js/dispatch_workflow.test.cjs +++ b/actions/setup/js/dispatch_workflow.test.cjs @@ -348,6 +348,26 @@ describe("dispatch_workflow handler factory", () => { }); }); + it("returns a report-only validation error when required input is missing before dispatch", async () => { + const config = { + workflows: ["haiku-printer"], + workflow_files: { + "haiku-printer": ".lock.yml", + }, + required_inputs: { + "haiku-printer": ["message"], + }, + }; + const handler = await main(config); + + const result = await handler({ type: "dispatch_workflow", workflow_name: "haiku-printer", inputs: {} }, {}); + + expect(result.success).toBe(false); + expect(result.reportOnly).toBe(true); + expect(result.error).toContain('missing required input "message"'); + expect(github.rest.actions.createWorkflowDispatch).not.toHaveBeenCalled(); + }); + it("should delay 5 seconds between dispatches", async () => { const config = { workflows: ["workflow1", "workflow2"], @@ -662,6 +682,28 @@ describe("dispatch_workflow handler factory", () => { expect(github.rest.actions.createWorkflowDispatch).toHaveBeenCalledTimes(1); }); + it("returns a report-only validation error when API reports missing required input", async () => { + const error = new Error("Unprocessable Entity"); + // @ts-ignore + error.status = 422; + // @ts-ignore + error.response = { data: { message: "Required input 'message' not provided" } }; + github.rest.actions.createWorkflowDispatch.mockRejectedValueOnce(error); + + const config = { + workflows: ["haiku-printer"], + workflow_files: { "haiku-printer": ".lock.yml" }, + }; + const handler = await main(config); + + const result = await handler({ type: "dispatch_workflow", workflow_name: "haiku-printer", inputs: {} }, {}); + + expect(result.success).toBe(false); + expect(result.reportOnly).toBe(true); + expect(result.error).toContain('missing required input "message"'); + expect(github.rest.actions.createWorkflowDispatch).toHaveBeenCalledTimes(1); + }); + it("dispatches to target-repo when configured", async () => { process.env.GITHUB_REF = "refs/heads/main"; diff --git a/actions/setup/js/safe_output_handler_manager.cjs b/actions/setup/js/safe_output_handler_manager.cjs index a1a43f6fd68..28c79dbe4ac 100644 --- a/actions/setup/js/safe_output_handler_manager.cjs +++ b/actions/setup/js/safe_output_handler_manager.cjs @@ -574,11 +574,11 @@ const REPORT_ONLY_FAILURE_TYPES = new Set(["assign_to_agent", "upload_artifact"] * Artifact uploads are best-effort and non-critical: a failed upload should not fail an * otherwise-successful run. * - * @param {{type?: string, success?: boolean, deferred?: boolean, skipped?: boolean, cancelled?: boolean}|null|undefined} result + * @param {{type?: string, success?: boolean, deferred?: boolean, skipped?: boolean, cancelled?: boolean, reportOnly?: boolean}|null|undefined} result * @returns {boolean} */ function isReportOnlyFailureResult(result) { - return isFailedProcessingResult(result) && !!(result?.type && REPORT_ONLY_FAILURE_TYPES.has(result.type)); + return isFailedProcessingResult(result) && (result?.reportOnly === true || !!(result?.type && REPORT_ONLY_FAILURE_TYPES.has(result.type))); } /** @@ -589,8 +589,8 @@ function isReportOnlyFailureResult(result) { */ function partitionFailureResults(results) { const failedResults = results.filter(isFailedProcessingResult); - const reportOnlyFailures = failedResults.filter(r => REPORT_ONLY_FAILURE_TYPES.has(r?.type ?? "")); - const fatalFailures = failedResults.filter(r => !REPORT_ONLY_FAILURE_TYPES.has(r?.type ?? "")); + const reportOnlyFailures = failedResults.filter(isReportOnlyFailureResult); + const fatalFailures = failedResults.filter(r => !isReportOnlyFailureResult(r)); return { fatalFailures, reportOnlyFailures }; } @@ -827,6 +827,7 @@ async function processMessages(messageHandlers, messages, onItemCreated = null) messageIndex: i, success: false, error: errorMsg, + ...(result.reportOnly === true ? { reportOnly: true } : {}), }); // Track code-push failures for fail-fast behaviour if (CODE_PUSH_TYPES.has(messageType)) { @@ -997,6 +998,9 @@ async function processMessages(messageHandlers, messages, onItemCreated = null) if (resultIndex >= 0) { results[resultIndex].success = false; results[resultIndex].error = errorMsg; + if (result.reportOnly === true) { + results[resultIndex].reportOnly = true; + } } continue; } diff --git a/actions/setup/js/safe_output_handler_manager.test.cjs b/actions/setup/js/safe_output_handler_manager.test.cjs index dc1a7dbf2b4..caf108d4548 100644 --- a/actions/setup/js/safe_output_handler_manager.test.cjs +++ b/actions/setup/js/safe_output_handler_manager.test.cjs @@ -162,6 +162,16 @@ describe("Safe Output Handler Manager", () => { ).toBe(false); }); + it("treats explicit reportOnly failures as report-only regardless of type", () => { + expect( + isReportOnlyFailureResult({ + type: "dispatch_workflow", + success: false, + reportOnly: true, + }) + ).toBe(true); + }); + it("partitions fatal failures away from assign_to_agent report-only failures", () => { const { fatalFailures, reportOnlyFailures } = partitionFailureResults([ { type: "assign_to_agent", success: false, error: "Insufficient permissions" }, @@ -184,6 +194,16 @@ describe("Safe Output Handler Manager", () => { expect(reportOnlyFailures).toEqual([{ type: "upload_artifact", success: false, error: "artifact twirp CreateArtifact failed (400)" }]); expect(fatalFailures).toEqual([{ type: "create_issue", success: false, error: "Validation failed" }]); }); + + it("partitions explicit reportOnly failures as report-only, not fatal", () => { + const { fatalFailures, reportOnlyFailures } = partitionFailureResults([ + { type: "dispatch_workflow", success: false, reportOnly: true, error: "Validation failed" }, + { type: "create_issue", success: false, error: "Fatal validation failed" }, + ]); + + expect(reportOnlyFailures).toEqual([{ type: "dispatch_workflow", success: false, reportOnly: true, error: "Validation failed" }]); + expect(fatalFailures).toEqual([{ type: "create_issue", success: false, error: "Fatal validation failed" }]); + }); }); describe("loadHandlers", () => { diff --git a/pkg/workflow/dispatch_workflow.go b/pkg/workflow/dispatch_workflow.go index ca9239ec83c..b583312b7fe 100644 --- a/pkg/workflow/dispatch_workflow.go +++ b/pkg/workflow/dispatch_workflow.go @@ -9,12 +9,13 @@ var dispatchWorkflowLog = logger.New("workflow:dispatch_workflow") // DispatchWorkflowConfig holds configuration for dispatching workflows from agent output type DispatchWorkflowConfig struct { BaseSafeOutputConfig `yaml:",inline"` - Workflows []string `yaml:"workflows,omitempty"` // List of workflow names (without .md extension) to allow dispatching - WorkflowFiles map[string]string `yaml:"workflow_files,omitempty"` // Map of workflow name to file extension (.lock.yml or .yml) - populated at compile time - AwContextWorkflows []string `yaml:"aw_context_workflows,omitempty"` // Workflows that declare aw_context in workflow_dispatch.inputs - populated at compile time - TargetRepoSlug string `yaml:"target-repo,omitempty"` // Target repository for cross-repo dispatch (owner/repo or GitHub Actions expression) - AllowedRepos []string `yaml:"allowed-repos,omitempty"` // Allowlist for cross-repository dispatch targets - TargetRef string `yaml:"target-ref,omitempty"` // Target ref for cross-repo dispatch; overrides the caller's GITHUB_REF + Workflows []string `yaml:"workflows,omitempty"` // List of workflow names (without .md extension) to allow dispatching + WorkflowFiles map[string]string `yaml:"workflow_files,omitempty"` // Map of workflow name to file extension (.lock.yml or .yml) - populated at compile time + RequiredInputs map[string][]string `yaml:"required_inputs,omitempty"` // Map of workflow name to required workflow_dispatch input names - populated at compile time + AwContextWorkflows []string `yaml:"aw_context_workflows,omitempty"` // Workflows that declare aw_context in workflow_dispatch.inputs - populated at compile time + TargetRepoSlug string `yaml:"target-repo,omitempty"` // Target repository for cross-repo dispatch (owner/repo or GitHub Actions expression) + AllowedRepos []string `yaml:"allowed-repos,omitempty"` // Allowlist for cross-repository dispatch targets + TargetRef string `yaml:"target-ref,omitempty"` // Target ref for cross-repo dispatch; overrides the caller's GITHUB_REF } // parseDispatchWorkflowConfig handles dispatch-workflow configuration diff --git a/pkg/workflow/dispatch_workflow_test.go b/pkg/workflow/dispatch_workflow_test.go index cb889fbcde6..36ce9d97ed7 100644 --- a/pkg/workflow/dispatch_workflow_test.go +++ b/pkg/workflow/dispatch_workflow_test.go @@ -312,6 +312,11 @@ func TestDispatchWorkflowFileExtensionResolution(t *testing.T) { lockWorkflow := `name: Lock Workflow on: workflow_dispatch: + inputs: + message: + description: Message to print + required: true + type: string jobs: test: runs-on: ubuntu-latest @@ -379,6 +384,10 @@ This workflow dispatches to different workflow types. "lock-test should use .lock.yml extension") assert.Equal(t, ".yml", workflowData.SafeOutputs.DispatchWorkflow.WorkflowFiles["yml-test"], "yml-test should use .yml extension") + assert.Equal(t, []string{"message"}, workflowData.SafeOutputs.DispatchWorkflow.RequiredInputs["lock-test"], + "lock-test should capture required workflow_dispatch inputs") + assert.Empty(t, workflowData.SafeOutputs.DispatchWorkflow.RequiredInputs["yml-test"], + "yml-test should not have required workflow_dispatch inputs") // Generate safe outputs config to verify workflow_files is included configJSON, err := generateSafeOutputsConfig(workflowData) @@ -395,11 +404,15 @@ This workflow dispatches to different workflow types. workflowFiles, ok := dispatchWorkflowConfig["workflow_files"].(map[string]any) require.True(t, ok, "workflow_files should be in dispatch_workflow config") + requiredInputs, ok := dispatchWorkflowConfig["required_inputs"].(map[string]any) + require.True(t, ok, "required_inputs should be in dispatch_workflow config") assert.Equal(t, ".lock.yml", workflowFiles["lock-test"], "lock-test extension should be in workflow_files") assert.Equal(t, ".yml", workflowFiles["yml-test"], "yml-test extension should be in workflow_files") + assert.Equal(t, []any{"message"}, requiredInputs["lock-test"], + "lock-test required inputs should be in required_inputs") } // TestDispatchWorkflowValidationWithoutAgenticWorkflowsTool tests that dispatch-workflow diff --git a/pkg/workflow/safe_outputs_dispatch.go b/pkg/workflow/safe_outputs_dispatch.go index a1b0910b70e..210c13002b8 100644 --- a/pkg/workflow/safe_outputs_dispatch.go +++ b/pkg/workflow/safe_outputs_dispatch.go @@ -1,6 +1,8 @@ package workflow import ( + "sort" + "github.com/github/gh-aw/pkg/logger" ) @@ -37,6 +39,9 @@ func populateDispatchWorkflowFiles(data *WorkflowData, markdownPath string) { if data.SafeOutputs.DispatchWorkflow.WorkflowFiles == nil { data.SafeOutputs.DispatchWorkflow.WorkflowFiles = make(map[string]string) } + if data.SafeOutputs.DispatchWorkflow.RequiredInputs == nil { + data.SafeOutputs.DispatchWorkflow.RequiredInputs = make(map[string][]string) + } for _, workflowName := range data.SafeOutputs.DispatchWorkflow.Workflows { // Find the workflow file @@ -65,6 +70,12 @@ func populateDispatchWorkflowFiles(data *WorkflowData, markdownPath string) { ) safeOutputsConfigLog.Printf("Workflow %s declares aw_context input", workflowName) } + + requiredInputs := extractRequiredDispatchInputs(fileResult, workflowName) + if len(requiredInputs) > 0 { + data.SafeOutputs.DispatchWorkflow.RequiredInputs[workflowName] = requiredInputs + safeOutputsConfigLog.Printf("Workflow %s has required dispatch inputs: %v", workflowName, requiredInputs) + } } } @@ -91,6 +102,38 @@ func workflowHasAwContextInput(fileResult *findWorkflowFileResult, workflowName return hasAwContext } +func extractRequiredDispatchInputs(fileResult *findWorkflowFileResult, workflowName string) []string { + var inputs map[string]any + var err error + + if fileResult.lockExists { + inputs, err = extractWorkflowDispatchInputs(fileResult.lockPath) + } else if fileResult.ymlExists { + inputs, err = extractWorkflowDispatchInputs(fileResult.ymlPath) + } else if fileResult.mdExists { + inputs, err = extractMDWorkflowDispatchInputs(fileResult.mdPath) + } else { + return nil + } + if err != nil { + safeOutputsConfigLog.Printf("Warning: error extracting required inputs for %s: %v", workflowName, err) + return nil + } + + required := make([]string, 0, len(inputs)) + for inputName, inputDef := range inputs { + inputMap, ok := inputDef.(map[string]any) + if !ok { + continue + } + if requiredVal, exists := inputMap["required"].(bool); exists && requiredVal { + required = append(required, inputName) + } + } + sort.Strings(required) + return required +} + // generateDispatchWorkflowTool generates an MCP tool definition for a specific workflow. // The tool will be named after the workflow (normalized to underscores) and accept // the workflow's defined workflow_dispatch inputs as parameters. diff --git a/pkg/workflow/safe_outputs_handler_registry.go b/pkg/workflow/safe_outputs_handler_registry.go index c4c76781d04..371a324ee53 100644 --- a/pkg/workflow/safe_outputs_handler_registry.go +++ b/pkg/workflow/safe_outputs_handler_registry.go @@ -639,6 +639,9 @@ var handlerRegistry = map[string]handlerBuilder{ if len(c.WorkflowFiles) > 0 { builder.AddDefault("workflow_files", c.WorkflowFiles) } + if len(c.RequiredInputs) > 0 { + builder.AddDefault("required_inputs", c.RequiredInputs) + } // Add aw_context_workflows list if it has entries if len(c.AwContextWorkflows) > 0 {