diff --git a/.github/workflows/dependabot-burner.lock.yml b/.github/workflows/dependabot-burner.lock.yml index d88cf2984d..dbb23adceb 100644 --- a/.github/workflows/dependabot-burner.lock.yml +++ b/.github/workflows/dependabot-burner.lock.yml @@ -19,12 +19,14 @@ # gh aw compile # For more information: https://github.com/github/gh-aw/blob/main/.github/aw/github-agentic-workflows.md # -# Automatically bundles Dependabot PRs by runtime and manifest, creates project items, and assigns them to Copilot for remediation with a "Review Required" status column # -# frontmatter-hash: 852bb37e752cb474bccc41d6942d925f6b2bd9588f560dc9694ab5d0702d6aa6 +# frontmatter-hash: 6e0fca12f8bed9a8517bf5358ecc83c96dbcf89f2da3aed33ce0d75a66a7695d name: "Dependabot Burner" "on": + schedule: + - cron: "55 0 * * 0" + # Friendly format: weekly (scattered) workflow_dispatch: permissions: {} @@ -36,6 +38,8 @@ run-name: "Dependabot Burner" jobs: activation: + needs: pre_activation + if: needs.pre_activation.outputs.activated == 'true' runs-on: ubuntu-slim permissions: contents: read @@ -71,7 +75,6 @@ jobs: contents: read issues: read pull-requests: read - security-events: read concurrency: group: "gh-aw-copilot-${{ github.workflow }}" env: @@ -158,7 +161,7 @@ jobs: actor: context.actor, event_name: context.eventName, staged: false, - allowed_domains: ["defaults","github"], + allowed_domains: ["defaults"], firewall_enabled: true, awf_version: "v0.13.12", awmg_version: "", @@ -203,12 +206,12 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs cat > /opt/gh-aw/safeoutputs/config.json << 'EOF' - {"create_issue":{"expires":168,"max":20},"create_project_status_update":{"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1},"update_project":{"max":50}} + {"create_issue":{"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1}} EOF cat > /opt/gh-aw/safeoutputs/tools.json << 'EOF' [ { - "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 20 issue(s) can be created. Title will be prefixed with \"[Dependabot Burner] \". Labels [dependabot-burner] will be automatically added. Assignees [copilot] will be automatically assigned.", + "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[dependabot-burner] \".", "inputSchema": { "additionalProperties": false, "properties": { @@ -289,129 +292,6 @@ jobs: }, "name": "noop" }, - { - "description": "Add or update items in GitHub Projects v2 boards. Can add issues/PRs to a project and update custom field values. Requires the project URL, content type (issue or pull_request), and content number.\n\nThree usage modes:\n1. Add/update project item: Requires project + content_type. For 'issue' or 'pull_request', also requires content_number. For 'draft_issue', requires draft_title.\n2. Create project fields: Requires project + operation='create_fields' + field_definitions.\n3. Create project view: Requires project + operation='create_view' + view.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "content_number": { - "description": "Issue or pull request number to add to the project. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123 for issue #123, or 456 in github.com/owner/repo/pull/456 for PR #456). Required when content_type is 'issue' or 'pull_request'.", - "type": "number" - }, - "content_type": { - "description": "Type of item to add to the project. Use 'issue' or 'pull_request' to add existing repo content, or 'draft_issue' to create a draft item inside the project. Required when operation is not specified.", - "enum": [ - "issue", - "pull_request", - "draft_issue" - ], - "type": "string" - }, - "create_if_missing": { - "description": "Whether to create the project if it doesn't exist. Defaults to false. Requires projects:write permission when true.", - "type": "boolean" - }, - "draft_body": { - "description": "Optional body for a Projects v2 draft issue (markdown). Only used when content_type is 'draft_issue'.", - "type": "string" - }, - "draft_title": { - "description": "Title for a Projects v2 draft issue. Required when content_type is 'draft_issue'.", - "type": "string" - }, - "field_definitions": { - "description": "Field definitions to create when operation is create_fields. Required when operation='create_fields'.", - "items": { - "additionalProperties": false, - "properties": { - "data_type": { - "description": "Field type. Use SINGLE_SELECT with options for enumerated values.", - "enum": [ - "TEXT", - "NUMBER", - "DATE", - "SINGLE_SELECT", - "ITERATION" - ], - "type": "string" - }, - "name": { - "description": "Field name to create (e.g., 'size', 'priority').", - "type": "string" - }, - "options": { - "description": "Options for SINGLE_SELECT fields.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "required": [ - "name", - "data_type" - ], - "type": "object" - }, - "type": "array" - }, - "fields": { - "description": "Custom field values to set on the project item (e.g., {'Status': 'In Progress', 'Priority': 'High'}). Field names must match custom fields defined in the project.", - "type": "object" - }, - "operation": { - "description": "Optional operation mode. Use create_fields to create required fields up-front, or create_view to add a project view. When omitted, the tool adds/updates project items.", - "enum": [ - "create_fields", - "create_view" - ], - "type": "string" - }, - "project": { - "description": "Full GitHub project URL (e.g., 'https://github.com/orgs/myorg/projects/42' or 'https://github.com/users/username/projects/5'). Project names or numbers alone are NOT accepted.", - "pattern": "^https://github\\.com/(orgs|users)/[^/]+/projects/\\d+$", - "type": "string" - }, - "view": { - "additionalProperties": false, - "description": "View definition to create when operation is create_view. Required when operation='create_view'.", - "properties": { - "filter": { - "type": "string" - }, - "layout": { - "enum": [ - "table", - "board", - "roadmap" - ], - "type": "string" - }, - "name": { - "type": "string" - }, - "visible_fields": { - "description": "Field IDs to show in the view (table/board only).", - "items": { - "type": "number" - }, - "type": "array" - } - }, - "required": [ - "name", - "layout" - ], - "type": "object" - } - }, - "required": [ - "project" - ], - "type": "object" - }, - "name": "update_project" - }, { "description": "Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.", "inputSchema": { @@ -438,50 +318,6 @@ jobs: "type": "object" }, "name": "missing_data" - }, - { - "description": "Create a status update on a GitHub Projects v2 board to communicate project progress. Use this when you need to provide stakeholder updates with status indicators, timeline information, and progress summaries. Status updates create a historical record of project progress tracked over time. Requires project URL, status indicator, dates, and markdown body describing progress/trends/findings.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "body": { - "description": "Status update body in markdown format describing progress, findings, trends, and next steps. Should provide stakeholders with clear understanding of project state.", - "type": "string" - }, - "project": { - "description": "Full GitHub project URL (e.g., 'https://github.com/orgs/myorg/projects/42' or 'https://github.com/users/username/projects/5'). Project names or numbers alone are NOT accepted.", - "pattern": "^https://github\\\\.com/(orgs|users)/[^/]+/projects/\\\\d+$", - "type": "string" - }, - "start_date": { - "description": "Optional project start date in YYYY-MM-DD format (e.g., '2026-01-06').", - "pattern": "^\\\\d{4}-\\\\d{2}-\\\\d{2}$", - "type": "string" - }, - "status": { - "description": "Status indicator for the project. Defaults to ON_TRACK. Values: ON_TRACK (progressing well), AT_RISK (has issues/blockers), OFF_TRACK (significantly behind), COMPLETE (finished), INACTIVE (paused/cancelled).", - "enum": [ - "ON_TRACK", - "AT_RISK", - "OFF_TRACK", - "COMPLETE", - "INACTIVE" - ], - "type": "string" - }, - "target_date": { - "description": "Optional project target/end date in YYYY-MM-DD format (e.g., '2026-12-31').", - "pattern": "^\\\\d{4}-\\\\d{2}-\\\\d{2}$", - "type": "string" - } - }, - "required": [ - "project", - "body" - ], - "type": "object" - }, - "name": "create_project_status_update" } ] EOF @@ -520,45 +356,6 @@ jobs: } } }, - "create_project_status_update": { - "defaultMax": 10, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65536 - }, - "project": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 512, - "pattern": "^https://github\\.com/(orgs|users)/[^/]+/projects/\\d+", - "patternError": "must be a full GitHub project URL (e.g., https://github.com/orgs/myorg/projects/42)" - }, - "start_date": { - "type": "string", - "pattern": "^\\d{4}-\\d{2}-\\d{2}$", - "patternError": "must be in YYYY-MM-DD format" - }, - "status": { - "type": "string", - "enum": [ - "INACTIVE", - "ON_TRACK", - "AT_RISK", - "OFF_TRACK", - "COMPLETE" - ] - }, - "target_date": { - "type": "string", - "pattern": "^\\d{4}-\\d{2}-\\d{2}$", - "patternError": "must be in YYYY-MM-DD format" - } - } - }, "missing_tool": { "defaultMax": 20, "fields": { @@ -590,49 +387,6 @@ jobs: "maxLength": 65000 } } - }, - "update_project": { - "defaultMax": 10, - "fields": { - "content_number": { - "optionalPositiveInteger": true - }, - "content_type": { - "type": "string", - "enum": [ - "issue", - "pull_request", - "draft_issue" - ] - }, - "draft_body": { - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "draft_title": { - "type": "string", - "sanitize": true, - "maxLength": 256 - }, - "fields": { - "type": "object" - }, - "issue": { - "optionalPositiveInteger": true - }, - "project": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 512, - "pattern": "^https://github\\.com/(orgs|users)/[^/]+/projects/\\d+", - "patternError": "must be a full GitHub project URL (e.g., https://github.com/orgs/myorg/projects/42)" - }, - "pull_request": { - "optionalPositiveInteger": true - } - } } } EOF @@ -710,7 +464,7 @@ jobs: "GITHUB_LOCKDOWN_MODE": "$GITHUB_MCP_LOCKDOWN", "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", "GITHUB_READ_ONLY": "1", - "GITHUB_TOOLSETS": "context,repos,issues,pull_requests,dependabot,projects" + "GITHUB_TOOLSETS": "context,repos,issues,pull_requests" } }, "safeoutputs": { @@ -858,27 +612,11 @@ jobs: - name: Execute GitHub Copilot CLI id: agentic_execution # Copilot CLI tool arguments (sorted): - # --allow-tool github - # --allow-tool safeoutputs - # --allow-tool shell(cat) - # --allow-tool shell(date) - # --allow-tool shell(echo) - # --allow-tool shell(grep) - # --allow-tool shell(head) - # --allow-tool shell(jq *) - # --allow-tool shell(ls) - # --allow-tool shell(pwd) - # --allow-tool shell(sort) - # --allow-tool shell(tail) - # --allow-tool shell(uniq) - # --allow-tool shell(wc) - # --allow-tool shell(yq) - # --allow-tool write timeout-minutes: 20 run: | set -o pipefail - sudo -E awf --enable-chroot --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains '*.githubusercontent.com,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,codeload.github.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-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.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' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.13.12 --skip-pull \ - -- '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool github --allow-tool safeoutputs --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq *)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' \ + sudo -E awf --enable-chroot --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains 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 --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.13.12 --skip-pull \ + -- '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' \ 2>&1 | tee /tmp/gh-aw/agent-stdio.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE @@ -956,7 +694,7 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,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,codeload.github.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-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.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" + GH_AW_ALLOWED_DOMAINS: "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" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} with: @@ -1199,7 +937,7 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: WORKFLOW_NAME: "Dependabot Burner" - WORKFLOW_DESCRIPTION: "Automatically bundles Dependabot PRs by runtime and manifest, creates project items, and assigns them to Copilot for remediation with a \"Review Required\" status column" + WORKFLOW_DESCRIPTION: "No description provided" HAS_PATCH: ${{ needs.agent.outputs.has_patch }} with: script: | @@ -1264,6 +1002,36 @@ jobs: path: /tmp/gh-aw/threat-detection/detection.log if-no-files-found: ignore + pre_activation: + runs-on: ubuntu-slim + permissions: + contents: read + outputs: + activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }} + steps: + - name: Checkout actions folder + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + sparse-checkout: | + actions + persist-credentials: false + - name: Setup Scripts + uses: ./actions/setup + with: + destination: /opt/gh-aw/actions + - name: Check team membership for workflow + id: check_membership + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + env: + GH_AW_REQUIRED_ROLES: admin,maintainer,write + with: + 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/check_membership.cjs'); + await main(); + safe_outputs: needs: - agent @@ -1294,7 +1062,6 @@ jobs: uses: ./actions/setup with: destination: /opt/gh-aw/actions - safe-output-projects: 'true' - name: Download agent output artifact continue-on-error: true uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 @@ -1311,27 +1078,12 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"assignees\":[\"copilot\"],\"expires\":168,\"labels\":[\"dependabot-burner\"],\"max\":20,\"title_prefix\":\"[Dependabot Burner] \"},\"create_project_status_update\":{\"github-token\":\"${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }}\",\"max\":1,\"project\":\"https://github.com/orgs/github/projects/24060\"},\"missing_data\":{},\"missing_tool\":{},\"update_project\":{\"github-token\":\"${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }}\",\"max\":50,\"project\":\"https://github.com/orgs/github/projects/24060\",\"views\":[{\"name\":\"Dependabot Alerts Board\",\"layout\":\"board\",\"filter\":\"is:open\"},{\"name\":\"Review Required\",\"layout\":\"board\",\"filter\":\"is:open status:\\\"Review Required\\\"\"},{\"name\":\"All Alerts Table\",\"layout\":\"table\"}]}}" - GH_AW_ASSIGN_COPILOT: "true" - GH_AW_PROJECT_URL: "https://github.com/orgs/github/projects/24060" - GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"max\":1,\"title_prefix\":\"[dependabot-burner] \"},\"missing_data\":{},\"missing_tool\":{}}" with: - github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} + github-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_handler_manager.cjs'); await main(); - - name: Assign Copilot to created issues - if: steps.process_safe_outputs.outputs.issues_to_assign_copilot != '' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_ISSUES_TO_ASSIGN_COPILOT: ${{ steps.process_safe_outputs.outputs.issues_to_assign_copilot }} - with: - 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/assign_copilot_to_created_issues.cjs'); - await main(); diff --git a/.github/workflows/dependabot-burner.md b/.github/workflows/dependabot-burner.md index 6a90738383..f5e71d4ef6 100644 --- a/.github/workflows/dependabot-burner.md +++ b/.github/workflows/dependabot-burner.md @@ -1,65 +1,16 @@ --- -name: Dependabot Burner -description: Automatically bundles Dependabot PRs by runtime and manifest, creates project items, and assigns them to Copilot for remediation with a "Review Required" status column - -on: - #schedule: daily - workflow_dispatch: - +on: weekly permissions: contents: read issues: read pull-requests: read - security-events: read - -network: - allowed: - - defaults - - github - tools: github: - toolsets: - - default - - dependabot - - projects - bash: - - "jq *" - safe-outputs: create-issue: - expires: 7d - title-prefix: "[Dependabot Burner] " - labels: [dependabot-burner] - assignees: [copilot] - max: 20 - group: false - update-project: - project: "https://github.com/orgs/github/projects/24060" - max: 50 - github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} - views: - - name: "Dependabot Alerts Board" - layout: board - filter: "is:open" - - name: "Review Required" - layout: board - filter: 'is:open status:"Review Required"' - - name: "All Alerts Table" - layout: table - - create-project-status-update: - project: "https://github.com/orgs/github/projects/24060" - max: 1 - github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} + title-prefix: '[dependabot-burner] ' --- - # Dependabot Burner -- Only create project views if they don't exist. -- Identify all open Dependabot pull requests. -- Group them by runtime and manifest file. -- Create a parent issue for each group, bundling the related PRs. -- Add each parent issue to the project board. -- Remove the individual PRs from the board once bundled. -- Assign each parent issue to Copilot. +- Find all open Dependabot PRs and add them to the project. +- Create bundle issues, each for exactly **one runtime + one manifest file**. diff --git a/.github/workflows/dependabot-project-manager.lock.yml b/.github/workflows/dependabot-project-manager.lock.yml deleted file mode 100644 index 8c41de6240..0000000000 --- a/.github/workflows/dependabot-project-manager.lock.yml +++ /dev/null @@ -1,1387 +0,0 @@ -# -# ___ _ _ -# / _ \ | | (_) -# | |_| | __ _ ___ _ __ | |_ _ ___ -# | _ |/ _` |/ _ \ '_ \| __| |/ __| -# | | | | (_| | __/ | | | |_| | (__ -# \_| |_/\__, |\___|_| |_|\__|_|\___| -# __/ | -# _ _ |___/ -# | | | | / _| | -# | | | | ___ _ __ _ __| |_| | _____ ____ -# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___| -# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ -# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ -# -# This file was automatically generated by gh-aw. DO NOT EDIT. -# -# To update this file, edit the corresponding .md file and run: -# gh aw compile -# For more information: https://github.com/github/gh-aw/blob/main/.github/aw/github-agentic-workflows.md -# -# Automatically bundles Dependabot PRs by runtime and manifest, creates project items, and assigns them to Copilot for remediation with a "Review Required" status column -# -# Resolved workflow manifest: -# Imports: -# - shared/mood.md -# -# frontmatter-hash: 3a91a286e566cd6f6e9b7370c5e41efbd4e4bc22aa02f2b3f54fc2b9486cee3c - -name: "Dependabot Project Manager" -"on": - workflow_dispatch: - -permissions: {} - -concurrency: - group: "gh-aw-${{ github.workflow }}" - -run-name: "Dependabot Project Manager" - -jobs: - activation: - runs-on: ubuntu-slim - permissions: - contents: read - outputs: - comment_id: "" - comment_repo: "" - steps: - - name: Checkout actions folder - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - sparse-checkout: | - actions - persist-credentials: false - - name: Setup Scripts - uses: ./actions/setup - with: - destination: /opt/gh-aw/actions - - name: Check workflow file timestamps - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_WORKFLOW_FILE: "dependabot-project-manager.lock.yml" - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs'); - await main(); - - agent: - needs: activation - runs-on: ubuntu-latest - permissions: - contents: read - issues: read - pull-requests: read - security-events: read - concurrency: - group: "gh-aw-copilot-${{ github.workflow }}" - env: - DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} - GH_AW_ASSETS_ALLOWED_EXTS: "" - GH_AW_ASSETS_BRANCH: "" - GH_AW_ASSETS_MAX_SIZE_KB: 0 - GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs - GH_AW_SAFE_OUTPUTS: /opt/gh-aw/safeoutputs/outputs.jsonl - GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json - GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json - outputs: - checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }} - has_patch: ${{ steps.collect_output.outputs.has_patch }} - model: ${{ steps.generate_aw_info.outputs.model }} - output: ${{ steps.collect_output.outputs.output }} - output_types: ${{ steps.collect_output.outputs.output_types }} - secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} - steps: - - name: Checkout actions folder - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - sparse-checkout: | - actions - persist-credentials: false - - name: Setup Scripts - uses: ./actions/setup - with: - destination: /opt/gh-aw/actions - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - name: Create gh-aw temp directory - run: bash /opt/gh-aw/actions/create_gh_aw_tmp_dir.sh - - name: Configure Git credentials - env: - REPO_NAME: ${{ github.repository }} - SERVER_URL: ${{ github.server_url }} - run: | - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git config --global user.name "github-actions[bot]" - # Re-authenticate git with GitHub token - SERVER_URL_STRIPPED="${SERVER_URL#https://}" - 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: Checkout PR branch - id: checkout-pr - if: | - github.event.pull_request - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - with: - github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_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/checkout_pr_branch.cjs'); - await main(); - - name: Generate agentic run info - id: generate_aw_info - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const fs = require('fs'); - - const awInfo = { - engine_id: "copilot", - engine_name: "GitHub Copilot CLI", - model: process.env.GH_AW_MODEL_AGENT_COPILOT || "", - version: "", - agent_version: "0.0.405", - workflow_name: "Dependabot Project Manager", - experimental: false, - supports_tools_allowlist: true, - supports_http_transport: true, - run_id: context.runId, - run_number: context.runNumber, - run_attempt: process.env.GITHUB_RUN_ATTEMPT, - repository: context.repo.owner + '/' + context.repo.repo, - ref: context.ref, - sha: context.sha, - actor: context.actor, - event_name: context.eventName, - staged: false, - allowed_domains: ["defaults","github"], - firewall_enabled: true, - awf_version: "v0.13.12", - awmg_version: "", - steps: { - firewall: "squid" - }, - created_at: new Date().toISOString() - }; - - // Write to /tmp/gh-aw directory to avoid inclusion in PR - const tmpPath = '/tmp/gh-aw/aw_info.json'; - fs.writeFileSync(tmpPath, JSON.stringify(awInfo, null, 2)); - console.log('Generated aw_info.json at:', tmpPath); - console.log(JSON.stringify(awInfo, null, 2)); - - // Set model as output for reuse in other steps/jobs - core.setOutput('model', awInfo.model); - - name: Validate COPILOT_GITHUB_TOKEN secret - id: validate-secret - run: /opt/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default - env: - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - - name: Install GitHub Copilot CLI - run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.405 - - name: Install awf binary - run: bash /opt/gh-aw/actions/install_awf_binary.sh v0.13.12 - - name: Determine automatic lockdown mode for GitHub MCP server - id: determine-automatic-lockdown - env: - TOKEN_CHECK: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} - if: env.TOKEN_CHECK != '' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - 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.13.12 ghcr.io/github/gh-aw-firewall/squid:0.13.12 ghcr.io/github/gh-aw-mcpg:v0.0.113 ghcr.io/github/github-mcp-server:v0.30.3 node:lts-alpine - - name: Write Safe Outputs Config - run: | - mkdir -p /opt/gh-aw/safeoutputs - mkdir -p /tmp/gh-aw/safeoutputs - mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > /opt/gh-aw/safeoutputs/config.json << 'EOF' - {"add_comment":{"max":10},"create_issue":{"max":1},"create_project_status_update":{"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1},"update_project":{"max":50}} - EOF - cat > /opt/gh-aw/safeoutputs/tools.json << 'EOF' - [ - { - "description": "Create a new GitHub issue for tracking bugs, feature requests, or tasks. Use this for actionable work items that need assignment, labeling, and status tracking. For reports, announcements, or status updates that don't require task tracking, use create_discussion instead. CONSTRAINTS: Maximum 1 issue(s) can be created. Assignees [copilot] will be automatically assigned.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "body": { - "description": "Detailed issue description in Markdown. Do NOT repeat the title as a heading since it already appears as the issue's h1. Include context, reproduction steps, or acceptance criteria as appropriate.", - "type": "string" - }, - "labels": { - "description": "Labels to categorize the issue (e.g., 'bug', 'enhancement'). Labels must exist in the repository.", - "items": { - "type": "string" - }, - "type": "array" - }, - "parent": { - "description": "Parent issue number for creating sub-issues. This is the numeric ID from the GitHub URL (e.g., 42 in github.com/owner/repo/issues/42). Can also be a temporary_id (e.g., 'aw_abc123def456') from a previously created issue in the same workflow run.", - "type": [ - "number", - "string" - ] - }, - "temporary_id": { - "description": "Unique temporary identifier for referencing this issue before it's created. Format: 'aw_' followed by 12 hex characters (e.g., 'aw_abc123def456'). Use '#aw_ID' in body text to reference other issues by their temporary_id; these are replaced with actual issue numbers after creation.", - "type": "string" - }, - "title": { - "description": "Concise issue title summarizing the bug, feature, or task. The title appears as the main heading, so keep it brief and descriptive.", - "type": "string" - } - }, - "required": [ - "title", - "body" - ], - "type": "object" - }, - "name": "create_issue" - }, - { - "description": "Add a comment to an existing GitHub issue, pull request, or discussion. Use this to provide feedback, answer questions, or add information to an existing conversation. For creating new items, use create_issue, create_discussion, or create_pull_request instead. CONSTRAINTS: Maximum 10 comment(s) can be added.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "body": { - "description": "The comment text in Markdown format. This is the 'body' field - do not use 'comment_body' or other variations. Provide helpful, relevant information that adds value to the conversation.", - "type": "string" - }, - "item_number": { - "description": "The issue, pull request, or discussion number to comment on. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123). If omitted, the tool will attempt to resolve the target from the current workflow context (triggering issue, PR, or discussion).", - "type": "number" - } - }, - "required": [ - "body" - ], - "type": "object" - }, - "name": "add_comment" - }, - { - "description": "Report that a tool or capability needed to complete the task is not available, or share any information you deem important about missing functionality or limitations. Use this when you cannot accomplish what was requested because the required functionality is missing or access is restricted.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "alternatives": { - "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).", - "type": "string" - }, - "reason": { - "description": "Explanation of why this tool is needed or what information you want to share about the limitation (max 256 characters).", - "type": "string" - }, - "tool": { - "description": "Optional: Name or description of the missing tool or capability (max 128 characters). Be specific about what functionality is needed.", - "type": "string" - } - }, - "required": [ - "reason" - ], - "type": "object" - }, - "name": "missing_tool" - }, - { - "description": "Log a transparency message when no significant actions are needed. Use this to confirm workflow completion and provide visibility when analysis is complete but no changes or outputs are required (e.g., 'No issues found', 'All checks passed'). This ensures the workflow produces human-visible output even when no other actions are taken.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "message": { - "description": "Status or completion message to log. Should explain what was analyzed and the outcome (e.g., 'Code review complete - no issues found', 'Analysis complete - all tests passing').", - "type": "string" - } - }, - "required": [ - "message" - ], - "type": "object" - }, - "name": "noop" - }, - { - "description": "Add or update items in GitHub Projects v2 boards. Can add issues/PRs to a project and update custom field values. Requires the project URL, content type (issue or pull_request), and content number.\n\nThree usage modes:\n1. Add/update project item: Requires project + content_type. For 'issue' or 'pull_request', also requires content_number. For 'draft_issue', requires draft_title.\n2. Create project fields: Requires project + operation='create_fields' + field_definitions.\n3. Create project view: Requires project + operation='create_view' + view.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "content_number": { - "description": "Issue or pull request number to add to the project. This is the numeric ID from the GitHub URL (e.g., 123 in github.com/owner/repo/issues/123 for issue #123, or 456 in github.com/owner/repo/pull/456 for PR #456). Required when content_type is 'issue' or 'pull_request'.", - "type": "number" - }, - "content_type": { - "description": "Type of item to add to the project. Use 'issue' or 'pull_request' to add existing repo content, or 'draft_issue' to create a draft item inside the project. Required when operation is not specified.", - "enum": [ - "issue", - "pull_request", - "draft_issue" - ], - "type": "string" - }, - "create_if_missing": { - "description": "Whether to create the project if it doesn't exist. Defaults to false. Requires projects:write permission when true.", - "type": "boolean" - }, - "draft_body": { - "description": "Optional body for a Projects v2 draft issue (markdown). Only used when content_type is 'draft_issue'.", - "type": "string" - }, - "draft_title": { - "description": "Title for a Projects v2 draft issue. Required when content_type is 'draft_issue'.", - "type": "string" - }, - "field_definitions": { - "description": "Field definitions to create when operation is create_fields. Required when operation='create_fields'.", - "items": { - "additionalProperties": false, - "properties": { - "data_type": { - "description": "Field type. Use SINGLE_SELECT with options for enumerated values.", - "enum": [ - "TEXT", - "NUMBER", - "DATE", - "SINGLE_SELECT", - "ITERATION" - ], - "type": "string" - }, - "name": { - "description": "Field name to create (e.g., 'size', 'priority').", - "type": "string" - }, - "options": { - "description": "Options for SINGLE_SELECT fields.", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "required": [ - "name", - "data_type" - ], - "type": "object" - }, - "type": "array" - }, - "fields": { - "description": "Custom field values to set on the project item (e.g., {'Status': 'In Progress', 'Priority': 'High'}). Field names must match custom fields defined in the project.", - "type": "object" - }, - "operation": { - "description": "Optional operation mode. Use create_fields to create required fields up-front, or create_view to add a project view. When omitted, the tool adds/updates project items.", - "enum": [ - "create_fields", - "create_view" - ], - "type": "string" - }, - "project": { - "description": "Full GitHub project URL (e.g., 'https://github.com/orgs/myorg/projects/42' or 'https://github.com/users/username/projects/5'). Project names or numbers alone are NOT accepted.", - "pattern": "^https://github\\.com/(orgs|users)/[^/]+/projects/\\d+$", - "type": "string" - }, - "view": { - "additionalProperties": false, - "description": "View definition to create when operation is create_view. Required when operation='create_view'.", - "properties": { - "filter": { - "type": "string" - }, - "layout": { - "enum": [ - "table", - "board", - "roadmap" - ], - "type": "string" - }, - "name": { - "type": "string" - }, - "visible_fields": { - "description": "Field IDs to show in the view (table/board only).", - "items": { - "type": "number" - }, - "type": "array" - } - }, - "required": [ - "name", - "layout" - ], - "type": "object" - } - }, - "required": [ - "project" - ], - "type": "object" - }, - "name": "update_project" - }, - { - "description": "Report that data or information needed to complete the task is not available. Use this when you cannot accomplish what was requested because required data, context, or information is missing.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "alternatives": { - "description": "Any workarounds, manual steps, or alternative approaches the user could take (max 256 characters).", - "type": "string" - }, - "context": { - "description": "Additional context about the missing data or where it should come from (max 256 characters).", - "type": "string" - }, - "data_type": { - "description": "Type or description of the missing data or information (max 128 characters). Be specific about what data is needed.", - "type": "string" - }, - "reason": { - "description": "Explanation of why this data is needed to complete the task (max 256 characters).", - "type": "string" - } - }, - "required": [], - "type": "object" - }, - "name": "missing_data" - }, - { - "description": "Create a status update on a GitHub Projects v2 board to communicate project progress. Use this when you need to provide stakeholder updates with status indicators, timeline information, and progress summaries. Status updates create a historical record of project progress tracked over time. Requires project URL, status indicator, dates, and markdown body describing progress/trends/findings.", - "inputSchema": { - "additionalProperties": false, - "properties": { - "body": { - "description": "Status update body in markdown format describing progress, findings, trends, and next steps. Should provide stakeholders with clear understanding of project state.", - "type": "string" - }, - "project": { - "description": "Full GitHub project URL (e.g., 'https://github.com/orgs/myorg/projects/42' or 'https://github.com/users/username/projects/5'). Project names or numbers alone are NOT accepted.", - "pattern": "^https://github\\\\.com/(orgs|users)/[^/]+/projects/\\\\d+$", - "type": "string" - }, - "start_date": { - "description": "Optional project start date in YYYY-MM-DD format (e.g., '2026-01-06').", - "pattern": "^\\\\d{4}-\\\\d{2}-\\\\d{2}$", - "type": "string" - }, - "status": { - "description": "Status indicator for the project. Defaults to ON_TRACK. Values: ON_TRACK (progressing well), AT_RISK (has issues/blockers), OFF_TRACK (significantly behind), COMPLETE (finished), INACTIVE (paused/cancelled).", - "enum": [ - "ON_TRACK", - "AT_RISK", - "OFF_TRACK", - "COMPLETE", - "INACTIVE" - ], - "type": "string" - }, - "target_date": { - "description": "Optional project target/end date in YYYY-MM-DD format (e.g., '2026-12-31').", - "pattern": "^\\\\d{4}-\\\\d{2}-\\\\d{2}$", - "type": "string" - } - }, - "required": [ - "project", - "body" - ], - "type": "object" - }, - "name": "create_project_status_update" - } - ] - EOF - cat > /opt/gh-aw/safeoutputs/validation.json << 'EOF' - { - "add_comment": { - "defaultMax": 1, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "item_number": { - "issueOrPRNumber": true - } - } - }, - "create_issue": { - "defaultMax": 1, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "labels": { - "type": "array", - "itemType": "string", - "itemSanitize": true, - "itemMaxLength": 128 - }, - "parent": { - "issueOrPRNumber": true - }, - "repo": { - "type": "string", - "maxLength": 256 - }, - "temporary_id": { - "type": "string" - }, - "title": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 128 - } - } - }, - "create_project_status_update": { - "defaultMax": 10, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65536 - }, - "project": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 512, - "pattern": "^https://github\\.com/(orgs|users)/[^/]+/projects/\\d+", - "patternError": "must be a full GitHub project URL (e.g., https://github.com/orgs/myorg/projects/42)" - }, - "start_date": { - "type": "string", - "pattern": "^\\d{4}-\\d{2}-\\d{2}$", - "patternError": "must be in YYYY-MM-DD format" - }, - "status": { - "type": "string", - "enum": [ - "INACTIVE", - "ON_TRACK", - "AT_RISK", - "OFF_TRACK", - "COMPLETE" - ] - }, - "target_date": { - "type": "string", - "pattern": "^\\d{4}-\\d{2}-\\d{2}$", - "patternError": "must be in YYYY-MM-DD format" - } - } - }, - "missing_tool": { - "defaultMax": 20, - "fields": { - "alternatives": { - "type": "string", - "sanitize": true, - "maxLength": 512 - }, - "reason": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 256 - }, - "tool": { - "type": "string", - "sanitize": true, - "maxLength": 128 - } - } - }, - "noop": { - "defaultMax": 1, - "fields": { - "message": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - } - } - }, - "update_project": { - "defaultMax": 10, - "fields": { - "content_number": { - "optionalPositiveInteger": true - }, - "content_type": { - "type": "string", - "enum": [ - "issue", - "pull_request", - "draft_issue" - ] - }, - "draft_body": { - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "draft_title": { - "type": "string", - "sanitize": true, - "maxLength": 256 - }, - "fields": { - "type": "object" - }, - "issue": { - "optionalPositiveInteger": true - }, - "project": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 512, - "pattern": "^https://github\\.com/(orgs|users)/[^/]+/projects/\\d+", - "patternError": "must be a full GitHub project URL (e.g., https://github.com/orgs/myorg/projects/42)" - }, - "pull_request": { - "optionalPositiveInteger": true - } - } - } - } - EOF - - name: Generate Safe Outputs MCP Server Config - id: safe-outputs-config - run: | - # Generate a secure random API key (360 bits of entropy, 40+ chars) - # Mask immediately to prevent timing vulnerabilities - API_KEY=$(openssl rand -base64 45 | tr -d '/+=') - echo "::add-mask::${API_KEY}" - - PORT=3001 - - # Set outputs for next steps - { - echo "safe_outputs_api_key=${API_KEY}" - echo "safe_outputs_port=${PORT}" - } >> "$GITHUB_OUTPUT" - - echo "Safe Outputs MCP server will run on port ${PORT}" - - - name: Start Safe Outputs MCP HTTP Server - id: safe-outputs-start - env: - DEBUG: '*' - GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }} - GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }} - GH_AW_SAFE_OUTPUTS_TOOLS_PATH: /opt/gh-aw/safeoutputs/tools.json - GH_AW_SAFE_OUTPUTS_CONFIG_PATH: /opt/gh-aw/safeoutputs/config.json - GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs - run: | - # Environment variables are set above to prevent template injection - export DEBUG - export GH_AW_SAFE_OUTPUTS_PORT - export GH_AW_SAFE_OUTPUTS_API_KEY - export GH_AW_SAFE_OUTPUTS_TOOLS_PATH - export GH_AW_SAFE_OUTPUTS_CONFIG_PATH - export GH_AW_MCP_LOG_DIR - - bash /opt/gh-aw/actions/start_safe_outputs_server.sh - - - name: Start MCP gateway - id: start-mcp-gateway - env: - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} - GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }} - GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }} - GITHUB_MCP_LOCKDOWN: ${{ steps.determine-automatic-lockdown.outputs.lockdown == 'true' && '1' || '0' }} - GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - run: | - set -eo pipefail - mkdir -p /tmp/gh-aw/mcp-config - - # Export gateway environment variables for MCP config and gateway script - export MCP_GATEWAY_PORT="80" - export MCP_GATEWAY_DOMAIN="host.docker.internal" - MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=') - echo "::add-mask::${MCP_GATEWAY_API_KEY}" - export MCP_GATEWAY_API_KEY - export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads" - mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}" - 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 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.0.113' - - mkdir -p /home/runner/.copilot - cat << MCPCONFIG_EOF | bash /opt/gh-aw/actions/start_mcp_gateway.sh - { - "mcpServers": { - "github": { - "type": "stdio", - "container": "ghcr.io/github/github-mcp-server:v0.30.3", - "env": { - "GITHUB_LOCKDOWN_MODE": "$GITHUB_MCP_LOCKDOWN", - "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", - "GITHUB_READ_ONLY": "1", - "GITHUB_TOOLSETS": "context,repos,issues,pull_requests,dependabot,projects" - } - }, - "safeoutputs": { - "type": "http", - "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT", - "headers": { - "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}" - } - } - }, - "gateway": { - "port": $MCP_GATEWAY_PORT, - "domain": "${MCP_GATEWAY_DOMAIN}", - "apiKey": "${MCP_GATEWAY_API_KEY}", - "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" - } - } - MCPCONFIG_EOF - - name: Generate workflow overview - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const { generateWorkflowOverview } = require('/opt/gh-aw/actions/generate_workflow_overview.cjs'); - await generateWorkflowOverview(core); - - name: Create prompt with built-in context - env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} - GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} - GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} - GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} - GH_AW_GITHUB_SERVER_URL: ${{ github.server_url }} - GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} - run: | - bash /opt/gh-aw/actions/create_prompt_first.sh - cat << 'PROMPT_EOF' > "$GH_AW_PROMPT" - - PROMPT_EOF - cat "/opt/gh-aw/prompts/temp_folder_prompt.md" >> "$GH_AW_PROMPT" - cat "/opt/gh-aw/prompts/markdown.md" >> "$GH_AW_PROMPT" - cat << 'PROMPT_EOF' >> "$GH_AW_PROMPT" - - GitHub API Access Instructions - - The gh CLI is NOT authenticated. Do NOT use gh commands for GitHub operations. - - - To create or modify GitHub resources (issues, discussions, pull requests, etc.), you MUST call the appropriate safe output tool. Simply writing content will NOT work - the workflow requires actual tool calls. - - Discover available tools from the safeoutputs MCP server. - - **Critical**: Tool calls write structured data that downstream jobs process. Without tool calls, follow-up actions will be skipped. - - **Note**: If you made no other safe output tool calls during this workflow execution, call the "noop" tool to provide a status message indicating completion or that no actions were needed. - - - - The following GitHub context information is available for this workflow: - {{#if __GH_AW_GITHUB_ACTOR__ }} - - **actor**: __GH_AW_GITHUB_ACTOR__ - {{/if}} - {{#if __GH_AW_GITHUB_REPOSITORY__ }} - - **repository**: __GH_AW_GITHUB_REPOSITORY__ - {{/if}} - {{#if __GH_AW_GITHUB_WORKSPACE__ }} - - **workspace**: __GH_AW_GITHUB_WORKSPACE__ - {{/if}} - {{#if __GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ }} - - **issue-number**: #__GH_AW_GITHUB_EVENT_ISSUE_NUMBER__ - {{/if}} - {{#if __GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ }} - - **discussion-number**: #__GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER__ - {{/if}} - {{#if __GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ }} - - **pull-request-number**: #__GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER__ - {{/if}} - {{#if __GH_AW_GITHUB_EVENT_COMMENT_ID__ }} - - **comment-id**: __GH_AW_GITHUB_EVENT_COMMENT_ID__ - {{/if}} - {{#if __GH_AW_GITHUB_RUN_ID__ }} - - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__ - {{/if}} - - - PROMPT_EOF - cat << 'PROMPT_EOF' >> "$GH_AW_PROMPT" - - PROMPT_EOF - cat << 'PROMPT_EOF' >> "$GH_AW_PROMPT" - {{#runtime-import .github/workflows/shared/mood.md}} - PROMPT_EOF - cat << 'PROMPT_EOF' >> "$GH_AW_PROMPT" - {{#runtime-import .github/workflows/dependabot-project-manager.md}} - PROMPT_EOF - - name: Substitute placeholders - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_GITHUB_ACTOR: ${{ github.actor }} - GH_AW_GITHUB_EVENT_COMMENT_ID: ${{ github.event.comment.id }} - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: ${{ github.event.discussion.number }} - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }} - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }} - GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} - GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} - GH_AW_GITHUB_SERVER_URL: ${{ github.server_url }} - GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} - with: - script: | - const substitutePlaceholders = require('/opt/gh-aw/actions/substitute_placeholders.cjs'); - - // Call the substitution function - return await substitutePlaceholders({ - file: process.env.GH_AW_PROMPT, - substitutions: { - GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, - GH_AW_GITHUB_EVENT_COMMENT_ID: process.env.GH_AW_GITHUB_EVENT_COMMENT_ID, - GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER: process.env.GH_AW_GITHUB_EVENT_DISCUSSION_NUMBER, - GH_AW_GITHUB_EVENT_ISSUE_NUMBER: process.env.GH_AW_GITHUB_EVENT_ISSUE_NUMBER, - GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER: process.env.GH_AW_GITHUB_EVENT_PULL_REQUEST_NUMBER, - GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, - GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, - GH_AW_GITHUB_SERVER_URL: process.env.GH_AW_GITHUB_SERVER_URL, - GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE - } - }); - - name: Interpolate variables and render templates - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} - GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} - GH_AW_GITHUB_SERVER_URL: ${{ github.server_url }} - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/interpolate_prompt.cjs'); - await main(); - - name: Validate prompt placeholders - env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - run: bash /opt/gh-aw/actions/validate_prompt_placeholders.sh - - name: Print prompt - env: - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - run: bash /opt/gh-aw/actions/print_prompt_summary.sh - - name: Clean git credentials - run: bash /opt/gh-aw/actions/clean_git_credentials.sh - - name: Execute GitHub Copilot CLI - id: agentic_execution - # Copilot CLI tool arguments (sorted): - # --allow-tool github - # --allow-tool safeoutputs - # --allow-tool shell(cat) - # --allow-tool shell(date) - # --allow-tool shell(echo) - # --allow-tool shell(grep) - # --allow-tool shell(head) - # --allow-tool shell(jq *) - # --allow-tool shell(ls) - # --allow-tool shell(pwd) - # --allow-tool shell(sort) - # --allow-tool shell(tail) - # --allow-tool shell(uniq) - # --allow-tool shell(wc) - # --allow-tool shell(yq) - # --allow-tool write - timeout-minutes: 30 - run: | - set -o pipefail - sudo -E awf --enable-chroot --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains '*.githubusercontent.com,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,codeload.github.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-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.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' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.13.12 --skip-pull \ - -- '/usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-tool github --allow-tool safeoutputs --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq *)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' \ - 2>&1 | tee /tmp/gh-aw/agent-stdio.log - env: - COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json - GH_AW_MODEL_AGENT_COPILOT: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || '' }} - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} - GITHUB_HEAD_REF: ${{ github.head_ref }} - GITHUB_REF_NAME: ${{ github.ref_name }} - GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} - GITHUB_WORKSPACE: ${{ github.workspace }} - XDG_CONFIG_HOME: /home/runner - - name: Configure Git credentials - env: - REPO_NAME: ${{ github.repository }} - SERVER_URL: ${{ github.server_url }} - run: | - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git config --global user.name "github-actions[bot]" - # Re-authenticate git with GitHub token - SERVER_URL_STRIPPED="${SERVER_URL#https://}" - 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: Copy Copilot session state files to logs - if: always() - continue-on-error: true - run: | - # Copy Copilot session state files to logs folder for artifact collection - # This ensures they are in /tmp/gh-aw/ where secret redaction can scan them - SESSION_STATE_DIR="$HOME/.copilot/session-state" - LOGS_DIR="/tmp/gh-aw/sandbox/agent/logs" - - if [ -d "$SESSION_STATE_DIR" ]; then - echo "Copying Copilot session state files from $SESSION_STATE_DIR to $LOGS_DIR" - mkdir -p "$LOGS_DIR" - cp -v "$SESSION_STATE_DIR"/*.jsonl "$LOGS_DIR/" 2>/dev/null || true - echo "Session state files copied successfully" - else - echo "No session-state directory found at $SESSION_STATE_DIR" - fi - - name: Stop MCP gateway - if: always() - continue-on-error: true - env: - MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} - MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }} - GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }} - run: | - bash /opt/gh-aw/actions/stop_mcp_gateway.sh "$GATEWAY_PID" - - name: Redact secrets in logs - if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs'); - await main(); - env: - GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN' - SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} - SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} - SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Upload Safe Outputs - if: always() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: safe-output - path: ${{ env.GH_AW_SAFE_OUTPUTS }} - if-no-files-found: warn - - name: Ingest agent output - id: collect_output - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,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,codeload.github.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-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.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" - GITHUB_SERVER_URL: ${{ github.server_url }} - GITHUB_API_URL: ${{ github.api_url }} - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/collect_ndjson_output.cjs'); - await main(); - - name: Upload sanitized agent output - if: always() && env.GH_AW_AGENT_OUTPUT - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: agent-output - path: ${{ env.GH_AW_AGENT_OUTPUT }} - if-no-files-found: warn - - name: Upload engine output files - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: agent_outputs - path: | - /tmp/gh-aw/sandbox/agent/logs/ - /tmp/gh-aw/redacted-urls.log - if-no-files-found: ignore - - name: Parse agent logs for step summary - if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/ - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/parse_copilot_log.cjs'); - await main(); - - name: Parse MCP gateway logs for step summary - if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/parse_mcp_gateway_log.cjs'); - await main(); - - name: Print firewall logs - if: always() - continue-on-error: true - env: - AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs - run: | - # Fix permissions on firewall logs so they can be uploaded as artifacts - # AWF runs with sudo, creating files owned by root - sudo chmod -R a+r /tmp/gh-aw/sandbox/firewall/logs 2>/dev/null || true - awf logs summary | tee -a "$GITHUB_STEP_SUMMARY" - - name: Upload agent artifacts - if: always() - continue-on-error: true - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: agent-artifacts - path: | - /tmp/gh-aw/aw-prompts/prompt.txt - /tmp/gh-aw/aw_info.json - /tmp/gh-aw/mcp-logs/ - /tmp/gh-aw/sandbox/firewall/logs/ - /tmp/gh-aw/agent-stdio.log - /tmp/gh-aw/agent/ - if-no-files-found: ignore - - conclusion: - needs: - - activation - - agent - - detection - - safe_outputs - if: (always()) && (needs.agent.result != 'skipped') - runs-on: ubuntu-slim - permissions: - contents: read - discussions: write - issues: write - pull-requests: write - outputs: - noop_message: ${{ steps.noop.outputs.noop_message }} - tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} - total_count: ${{ steps.missing_tool.outputs.total_count }} - steps: - - name: Checkout actions folder - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - sparse-checkout: | - actions - persist-credentials: false - - name: Setup Scripts - uses: ./actions/setup - with: - destination: /opt/gh-aw/actions - - name: Debug job inputs - env: - COMMENT_ID: ${{ needs.activation.outputs.comment_id }} - COMMENT_REPO: ${{ needs.activation.outputs.comment_repo }} - AGENT_OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }} - AGENT_CONCLUSION: ${{ needs.agent.result }} - run: | - echo "Comment ID: $COMMENT_ID" - echo "Comment Repo: $COMMENT_REPO" - echo "Agent Output Types: $AGENT_OUTPUT_TYPES" - echo "Agent Conclusion: $AGENT_CONCLUSION" - - name: Download agent output artifact - continue-on-error: true - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 - with: - name: agent-output - path: /tmp/gh-aw/safeoutputs/ - - name: Setup agent output environment variable - run: | - 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 No-Op Messages - id: noop - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_NOOP_MAX: 1 - GH_AW_WORKFLOW_NAME: "Dependabot Project Manager" - with: - github-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/noop.cjs'); - await main(); - - name: Record Missing Tool - id: missing_tool - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_WORKFLOW_NAME: "Dependabot Project Manager" - with: - github-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/missing_tool.cjs'); - await main(); - - name: Handle Agent Failure - id: handle_agent_failure - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_WORKFLOW_NAME: "Dependabot Project Manager" - GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} - GH_AW_WORKFLOW_ID: "dependabot-project-manager" - GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.agent.outputs.secret_verification_result }} - GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }} - with: - github-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/handle_agent_failure.cjs'); - await main(); - - name: Handle No-Op Message - id: handle_noop_message - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_WORKFLOW_NAME: "Dependabot Project Manager" - GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} - GH_AW_NOOP_MESSAGE: ${{ steps.noop.outputs.noop_message }} - GH_AW_NOOP_REPORT_AS_ISSUE: "true" - with: - github-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/handle_noop_message.cjs'); - await main(); - - name: Update reaction comment with completion status - id: conclusion - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} - GH_AW_COMMENT_REPO: ${{ needs.activation.outputs.comment_repo }} - GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_AW_WORKFLOW_NAME: "Dependabot Project Manager" - GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} - GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.result }} - with: - github-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/notify_comment_error.cjs'); - await main(); - - detection: - needs: agent - if: needs.agent.outputs.output_types != '' || needs.agent.outputs.has_patch == 'true' - runs-on: ubuntu-latest - permissions: - contents: read - concurrency: - group: "gh-aw-copilot-${{ github.workflow }}" - timeout-minutes: 10 - outputs: - success: ${{ steps.parse_results.outputs.success }} - steps: - - name: Checkout actions folder - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - sparse-checkout: | - actions - persist-credentials: false - - name: Setup Scripts - uses: ./actions/setup - with: - destination: /opt/gh-aw/actions - - name: Download agent artifacts - continue-on-error: true - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 - with: - name: agent-artifacts - path: /tmp/gh-aw/threat-detection/ - - name: Download agent output artifact - continue-on-error: true - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 - with: - name: agent-output - path: /tmp/gh-aw/threat-detection/ - - name: Echo agent output types - env: - AGENT_OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }} - run: | - echo "Agent output-types: $AGENT_OUTPUT_TYPES" - - name: Setup threat detection - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - WORKFLOW_NAME: "Dependabot Project Manager" - WORKFLOW_DESCRIPTION: "Automatically bundles Dependabot PRs by runtime and manifest, creates project items, and assigns them to Copilot for remediation with a \"Review Required\" status column" - HAS_PATCH: ${{ needs.agent.outputs.has_patch }} - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/setup_threat_detection.cjs'); - await main(); - - name: Ensure threat-detection directory and log - run: | - mkdir -p /tmp/gh-aw/threat-detection - touch /tmp/gh-aw/threat-detection/detection.log - - name: Validate COPILOT_GITHUB_TOKEN secret - id: validate-secret - run: /opt/gh-aw/actions/validate_multi_secret.sh COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default - env: - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - - name: Install GitHub Copilot CLI - run: /opt/gh-aw/actions/install_copilot_cli.sh 0.0.405 - - name: Execute GitHub Copilot CLI - id: agentic_execution - # Copilot CLI tool arguments (sorted): - # --allow-tool shell(cat) - # --allow-tool shell(grep) - # --allow-tool shell(head) - # --allow-tool shell(jq) - # --allow-tool shell(ls) - # --allow-tool shell(tail) - # --allow-tool shell(wc) - timeout-minutes: 20 - run: | - set -o pipefail - COPILOT_CLI_INSTRUCTION="$(cat /tmp/gh-aw/aw-prompts/prompt.txt)" - mkdir -p /tmp/ - mkdir -p /tmp/gh-aw/ - mkdir -p /tmp/gh-aw/agent/ - mkdir -p /tmp/gh-aw/sandbox/agent/logs/ - copilot --add-dir /tmp/ --add-dir /tmp/gh-aw/ --add-dir /tmp/gh-aw/agent/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-tool 'shell(cat)' --allow-tool 'shell(grep)' --allow-tool 'shell(head)' --allow-tool 'shell(jq)' --allow-tool 'shell(ls)' --allow-tool 'shell(tail)' --allow-tool 'shell(wc)' --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$COPILOT_CLI_INSTRUCTION"${GH_AW_MODEL_DETECTION_COPILOT:+ --model "$GH_AW_MODEL_DETECTION_COPILOT"} 2>&1 | tee /tmp/gh-aw/threat-detection/detection.log - env: - COPILOT_AGENT_RUNNER_TYPE: STANDALONE - COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} - GH_AW_MODEL_DETECTION_COPILOT: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || '' }} - GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt - GITHUB_HEAD_REF: ${{ github.head_ref }} - GITHUB_REF_NAME: ${{ github.ref_name }} - GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} - GITHUB_WORKSPACE: ${{ github.workspace }} - XDG_CONFIG_HOME: /home/runner - - name: Parse threat detection results - id: parse_results - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - script: | - const { setupGlobals } = require('/opt/gh-aw/actions/setup_globals.cjs'); - setupGlobals(core, github, context, exec, io); - const { main } = require('/opt/gh-aw/actions/parse_threat_detection_results.cjs'); - await main(); - - name: Upload threat detection log - if: always() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: threat-detection.log - path: /tmp/gh-aw/threat-detection/detection.log - if-no-files-found: ignore - - safe_outputs: - needs: - - agent - - detection - if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.detection.outputs.success == 'true') - runs-on: ubuntu-slim - permissions: - contents: read - discussions: write - issues: write - pull-requests: write - timeout-minutes: 15 - env: - GH_AW_ENGINE_ID: "copilot" - GH_AW_WORKFLOW_ID: "dependabot-project-manager" - GH_AW_WORKFLOW_NAME: "Dependabot Project Manager" - outputs: - create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }} - create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }} - process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }} - process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }} - steps: - - name: Checkout actions folder - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - sparse-checkout: | - actions - persist-credentials: false - - name: Setup Scripts - uses: ./actions/setup - with: - destination: /opt/gh-aw/actions - safe-output-projects: 'true' - - name: Download agent output artifact - continue-on-error: true - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 - with: - name: agent-output - path: /tmp/gh-aw/safeoutputs/ - - name: Setup agent output environment variable - run: | - 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 - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":10},\"create_issue\":{\"assignees\":[\"copilot\"],\"max\":1},\"create_project_status_update\":{\"github-token\":\"${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }}\",\"max\":1,\"project\":\"https://github.com/orgs/github/projects/24060\"},\"missing_data\":{},\"missing_tool\":{},\"update_project\":{\"github-token\":\"${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }}\",\"max\":50,\"project\":\"https://github.com/orgs/github/projects/24060\",\"views\":[{\"name\":\"Dependabot Alerts Board\",\"layout\":\"board\",\"filter\":\"is:open\"},{\"name\":\"Review Required\",\"layout\":\"board\",\"filter\":\"is:open status:\\\"Review Required\\\"\"},{\"name\":\"All Alerts Table\",\"layout\":\"table\"}]}}" - GH_AW_ASSIGN_COPILOT: "true" - GH_AW_PROJECT_URL: "https://github.com/orgs/github/projects/24060" - GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} - with: - 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'); - await main(); - - name: Assign Copilot to created issues - if: steps.process_safe_outputs.outputs.issues_to_assign_copilot != '' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - env: - GH_AW_ISSUES_TO_ASSIGN_COPILOT: ${{ steps.process_safe_outputs.outputs.issues_to_assign_copilot }} - with: - 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/assign_copilot_to_created_issues.cjs'); - await main(); - diff --git a/.github/workflows/dependabot-project-manager.md b/.github/workflows/dependabot-project-manager.md deleted file mode 100644 index 556b38f622..0000000000 --- a/.github/workflows/dependabot-project-manager.md +++ /dev/null @@ -1,450 +0,0 @@ ---- -name: Dependabot Project Manager -description: Automatically bundles Dependabot PRs by runtime and manifest, creates project items, and assigns them to Copilot for remediation with a "Review Required" status column -on: - #schedule: daily - workflow_dispatch: - -timeout-minutes: 30 - -permissions: - contents: read - issues: read - pull-requests: read - security-events: read - -network: - allowed: - - defaults - - github - -tools: - github: - toolsets: - - default - - dependabot - - projects - bash: - - "jq *" - -safe-outputs: - update-project: - project: "https://github.com/orgs/github/projects/24060" - max: 50 - github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} - views: - - name: "Dependabot Alerts Board" - layout: board - filter: "is:open" - - name: "Review Required" - layout: board - filter: 'is:open status:"Review Required"' - - name: "All Alerts Table" - layout: table - - create-project-status-update: - project: "https://github.com/orgs/github/projects/24060" - max: 1 - github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} - - create-issue: - expires: 7d - title-prefix: "[Dependabot Bundle] " - labels: [dependencies, dependabot] - assignees: copilot # Automatically assigns Copilot when creating issues - max: 20 - group: false - - add-comment: - max: 10 -imports: - - shared/mood.md ---- - -# Dependabot Project Manager - -You are the Dependabot Project Manager - an intelligent system that automatically organizes Dependabot PRs into manageable bundles, tracks them on a GitHub Projects board, and coordinates remediation work with Copilot agents. - -## Objective - -Reduce dependency update resolution time by: -1. Automatically grouping Dependabot PRs by runtime (npm, pip, go, etc.) and manifest file -2. Creating trackable work items on a GitHub Projects board -3. Assigning bundles to Copilot agents for review and merging -4. Providing clear visibility into PR status with a "Review Required" column for PRs that need human approval - -## Task Overview - -When triggered (daily or manually), perform the following workflow: - -### Phase 1: Fetch Dependabot PRs - -1. **Query Dependabot PRs** for repository ${{ github.repository }} using GitHub tools - - Use `search_pull_requests` or `list_pull_requests` to find PRs created by dependabot[bot] - - Filter: `author:dependabot[bot] is:pr is:open` -2. **Filter for open PRs** (not closed or merged) -3. **Collect PR details** including: - - PR number, title, and URL - - Package name and ecosystem (npm, pip, go, maven, etc.) from PR title - - Current version and target version from PR title/body - - Manifest file path (extracted from PR title or branch name) - - PR description and labels - - Creation date and last update date - -### Phase 2: Bundle PRs by Runtime and Manifest - -1. **Group PRs** by two criteria: - - Primary grouping: Runtime/ecosystem (npm, pip, go, maven, etc.) extracted from PR metadata - - Secondary grouping: Manifest file path (extracted from PR title, branch name, or files changed) - - Example: Dependabot PR titles often follow pattern: "Bump package-name in /path/to/manifest" - -2. **Create bundle structure** for each group: - - Bundle ID: `{runtime}-{manifest-basename}` (e.g., "npm-package.json", "go-go.mod") - - List of PRs in the bundle with PR numbers and URLs - - Total PR count and update type breakdown (patch/minor/major) - - Unique manifest file path - -3. **Prioritize bundles** based on: - - Security updates (marked with security labels) get highest priority - - Runtime criticality (prioritize: go > npm > pip > others) - - Age of PRs (older PRs should be reviewed first) - -### Phase 3: Create or Update Project Items - -For each bundle identified in Phase 2: - -1. **Create a draft issue in the project** using `update_project`: - ```javascript - update_project({ - project: "https://github.com/orgs/github/projects/24060", - content_type: "draft_issue", - draft_title: "[{runtime}] {manifest} - {count} PR(s)", - draft_body: `## Bundle Summary - - **Runtime**: {runtime} - **Manifest**: {manifest_path} - **PR Count**: {total} - **Update Types**: {patch_count} patch, {minor_count} minor, {major_count} major - - ## PRs in This Bundle - - {pr_list_with_details_and_links} - - ## Recommended Action - - 1. Review each PR in the bundle - 2. Check for breaking changes and compatibility issues - 3. Review and approve PRs that are safe to merge - 4. Test PRs locally if needed - 5. Merge approved PRs or request changes - 6. Move this item to "Review Required" when PRs need human review - - ## Notes - - - Automated bundle created by Dependabot Project Manager - - Bundle ID: {bundle_id} - - Created: {timestamp}`, - fields: { - "Status": "Todo", - "Priority": "{priority}", // High (security), Medium (normal), Low (patch-only) - "Runtime": "{runtime}", - "Manifest": "{manifest_basename}", - "PR Count": "{total}", - "Update Type": "{primary_update_type}" // Security, Minor, Patch - } - }) - ``` - -2. **Set appropriate fields**: - - **Status**: "Todo" (new bundles start here) - - **Priority**: Based on security labels and update type (Security → Minor → Patch) - - **Runtime**: The ecosystem (npm, pip, go, etc.) - - **Manifest**: Basename of manifest file - - **PR Count**: Number of PRs in bundle - - **Update Type**: Primary update type (Security, Minor, Patch, Major) - -3. **Handle existing bundles**: - - If a bundle for the same runtime+manifest already exists in the project (check by searching draft issues with matching title pattern), update it instead of creating a new one - - Update the PR list and fields to reflect current state - -### Phase 4: Create GitHub Issues for Copilot Assignment - -For each bundle, create a GitHub issue that will be automatically assigned to the Copilot agent via the `assignees: copilot` configuration in the workflow's frontmatter. - -1. **Create issue** using `create_issue`: - ```javascript - create_issue({ - title: "Review and merge {runtime} dependency PRs in {manifest}", - body: `## Dependabot PR Bundle - - This issue tracks Dependabot PRs for {manifest_path} that need to be reviewed and merged. - - **Bundle ID**: {bundle_id} - **Runtime**: {runtime} - **PR Count**: {total} - - ## PRs to Review - - {pr_list_with_links_and_descriptions} - - ## Task - - 1. Review each Dependabot PR in the bundle - 2. Check for breaking changes in changelogs - 3. Verify tests pass on each PR - 4. Approve and merge PRs that are safe - 5. Comment on PRs that need changes or investigation - 6. Update this issue with merge status - - ## Acceptance Criteria - - - [ ] All PRs reviewed for compatibility - - [ ] Safe PRs approved and merged - - [ ] Problematic PRs have comments explaining issues - - [ ] Project item moved to "Done" when complete - - **Note**: This issue will be automatically assigned to @copilot via the workflow's safe-output configuration. - **Project**: See the corresponding project item for tracking`, - labels: ["dependencies", "dependabot", "automation"] - }) - ``` - -2. **Link issue to project item**: After creating the issue, add it to the project using `update_project` with `content_type: "issue"` and the issue number - -### Phase 5: Create Status Update - -Create a project status update summarizing the run: - -```javascript -create_project_status_update({ - project: "https://github.com/orgs/github/projects/24060", - status: "ON_TRACK", // or "AT_RISK" if many PRs are pending - start_date: "{today}", - target_date: "{today_plus_7_days}", - body: `## Dependabot PR Summary - -**Run Date**: {timestamp} -**Repository**: ${{ github.repository }} - -### Metrics - -- **Total Open PRs**: {total_prs} -- **Bundles Created/Updated**: {bundle_count} -- **Security Updates**: {security_count} -- **Major Updates**: {major_count} -- **Minor Updates**: {minor_count} -- **Patch Updates**: {patch_count} - -### Bundles by Runtime - -{runtime_breakdown_table} - -### Next Steps - -1. Copilot agents will review assigned PR bundles -2. Safe PRs will be approved and merged -3. Items will move to "Review Required" when PRs need human review -4. Human reviewers should monitor the "Review Required" column - -### Recommendations - -{any_urgent_notes_or_recommendations} - ---- -*Automated by Dependabot Project Manager - [{workflow_name}]({run_url})*` -}) -``` - -## Bundle Format Guidelines - -When formatting PR details in bundle descriptions: - -**Use this format for each PR:** -```markdown -### {update_type_emoji} {package_name} (#{pr_number}) - -- **Current Version**: {current_version} -- **Target Version**: {target_version} -- **Update Type**: {patch/minor/major} -- **Security**: {yes/no} -- **PR Link**: {pr_url} -- **Status**: {open/approved/changes_requested} -``` - -**Update Type Emojis:** -- Security: 🔴 -- Major: 🟠 -- Minor: 🟡 -- Patch: 🟢 - -## Project Board Structure - -The workflow creates/maintains these views: - -1. **Dependabot Alerts Board** (Board layout) - - Group by: Status - - Columns: Todo, In Progress, Review Required, Done - - Shows all open PR bundles - -2. **Review Required** (Board layout) - - Filtered view showing only items in "Review Required" status - - This is where PRs ready for human review appear - - Stakeholders should monitor this view daily - -3. **All Alerts Table** (Table layout) - - Shows all PR bundles with detailed fields - - Useful for sorting and filtering by runtime, update type, or manifest - -## Status Column Workflow - -PR bundles move through these statuses: - -1. **Todo**: Newly created bundles waiting for Copilot agent -2. **In Progress**: Copilot is actively reviewing PRs -3. **Review Required**: PRs reviewed, waiting for human approval/merge decision (KEY COLUMN) -4. **Done**: All PRs reviewed and merged or closed - -## Field Definitions - -The workflow uses these custom fields (will be created if they don't exist): - -- **Status** (Single select): Todo, In Progress, Review Required, Done -- **Priority** (Single select): High, Medium, Low -- **Runtime** (Single select): npm, pip, go, maven, gradle, composer, nuget -- **Manifest** (Text): Basename of manifest file -- **PR Count** (Number): Number of PRs in bundle -- **Update Type** (Single select): Security, Major, Minor, Patch (primary type in bundle) - -## Important Notes - -1. **Required GitHub Token**: This workflow requires a special token to be configured as a secret: - - **`GH_AW_PROJECT_GITHUB_TOKEN`**: Required for GitHub Projects v2 operations - - PAT or GitHub App token with Projects (read/write) permissions - - Used by `update-project` and `create-project-status-update` safe outputs - - See: https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token - -2. **Copilot Assignment**: Issues are automatically assigned to @copilot when created via the `assignees: copilot` configuration in the `create-issue` safe output. This uses the default GitHub Actions token and requires no additional configuration. - -3. **Bundle Deduplication**: Check if a bundle already exists before creating a new one to avoid duplicates - -4. **PR Extraction**: Dependabot PR titles typically follow patterns like "Bump package-name from X.Y.Z to A.B.C in /path/to/manifest" - use these patterns to extract runtime, package, versions, and manifest paths - -5. **Human Review**: The "Review Required" status is the key handoff point between automated review and human merge decisions - -## Success Metrics - -- PR review time: Target <7 days from bundle creation to PR merge -- Bundle processing rate: >90% of bundles reviewed within 1 day -- Review Required queue: Target <5 items waiting for human review -- Merge success rate: >90% of reviewed PRs merged successfully - -## Example Outputs - -### Example Bundle Draft Issue - -```markdown -## Bundle Summary - -**Runtime**: npm -**Manifest**: package.json -**PR Count**: 3 -**Update Types**: 1 minor, 2 patch - -## PRs in This Bundle - -### 🟡 axios (#1234) - -- **Current Version**: 0.21.1 -- **Target Version**: 0.22.0 -- **Update Type**: Minor -- **Security**: No -- **PR Link**: https://github.com/github/gh-aw/pull/1234 -- **Status**: Open - -### 🟢 lodash (#1235) - -- **Current Version**: 4.17.19 -- **Target Version**: 4.17.21 -- **Update Type**: Patch -- **Security**: No -- **PR Link**: https://github.com/github/gh-aw/pull/1235 -- **Status**: Open - -### 🟢 minimist (#1236) - -- **Current Version**: 1.2.5 -- **Target Version**: 1.2.6 -- **Update Type**: Patch -- **Security**: No -- **PR Link**: https://github.com/github/gh-aw/pull/1236 -- **Status**: Open - -## Recommended Action - -1. Review each PR in the bundle -2. Check for breaking changes and compatibility issues -3. Review and approve PRs that are safe to merge -4. Test PRs locally if needed -5. Merge approved PRs or request changes -6. Move this item to "Review Required" when PRs need human review - -## Notes - -- Automated bundle created by Dependabot Project Manager -- Bundle ID: npm-package.json -- Created: 2026-02-06T16:45:00Z -``` - -### Example Status Update - -```markdown -## Dependabot PR Summary - -**Run Date**: 2026-02-06T16:45:00Z -**Repository**: github/gh-aw - -### Metrics - -- **Total Open PRs**: 12 -- **Bundles Created/Updated**: 4 -- **Security Updates**: 1 -- **Major Updates**: 0 -- **Minor Updates**: 3 -- **Patch Updates**: 8 - -### Bundles by Runtime - -| Runtime | Bundles | PRs | Primary Update Type | -|---------|---------|-----|---------------------| -| npm | 2 | 6 | Minor | -| go | 1 | 4 | Patch | -| pip | 1 | 2 | Patch | - -### Next Steps - -1. Copilot agents will review assigned PR bundles -2. Safe PRs will be approved and merged -3. Items will move to "Review Required" when PRs need human review -4. Human reviewers should monitor the "Review Required" column - -### Recommendations - -- npm bundles have minor updates - review for breaking changes -- All go and pip updates are patches - safe to merge after review -- Monitor the "Review Required" column daily for PRs needing approval - ---- -*Automated by Dependabot Project Manager - [dependabot-project-manager](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})* -``` - -## Troubleshooting - -**No PRs found**: If Dependabot returns no open PRs, create a project status update noting "No open Dependabot PRs - all dependencies are up to date" and exit successfully. - -**Project permission errors**: Ensure the `GH_AW_PROJECT_GITHUB_TOKEN` secret has Projects write permissions and is correctly configured. - -**Too many bundles**: If there are >20 bundles, prioritize by security updates and update type, and create issues for the top 20 only. Create a status update noting the overflow. - -**Duplicate bundles**: Always check if a bundle with the same runtime+manifest combination already exists before creating a new one. Update existing items instead. - -**PR parsing errors**: Dependabot PR titles follow patterns like "Bump {package} from {old} to {new} in {path}". If parsing fails, fall back to extracting information from PR files changed or body content.