diff --git a/.github/workflows/smoke-project.lock.yml b/.github/workflows/smoke-project.lock.yml index 52f518295f5..0ac693ac045 100644 --- a/.github/workflows/smoke-project.lock.yml +++ b/.github/workflows/smoke-project.lock.yml @@ -21,33 +21,41 @@ # # Smoke Project - Test project operations # -# Resolved workflow manifest: -# Imports: -# - shared/gh.md -# - shared/mood.md -# - shared/reporting.md -# -# frontmatter-hash: 444a34a300c5972bb914d3c10b44ef630d57544b9654a07681fed0038bf51692 +# frontmatter-hash: e59c37d5c92621af3a7b691c7bd176c90a12df52fd76c0a2e90781db9475c727 name: "Smoke Project" "on": - workflow_dispatch: + pull_request: + # names: # Label filtering applied via job conditions + # - smoke # Label filtering applied via job conditions + types: + - labeled + workflow_dispatch: null permissions: {} concurrency: - group: "gh-aw-${{ github.workflow }}" + group: "gh-aw-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}" + cancel-in-progress: true run-name: "Smoke Project" jobs: activation: + needs: pre_activation + if: > + (needs.pre_activation.outputs.activated == 'true') && (((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.id == github.repository_id)) && + ((github.event_name != 'pull_request') || ((github.event.action != 'labeled') || (github.event.label.name == 'smoke')))) runs-on: ubuntu-slim permissions: contents: read + discussions: write + issues: write + pull-requests: write outputs: - comment_id: "" - comment_repo: "" + comment_id: ${{ steps.add-comment.outputs.comment-id }} + comment_repo: ${{ steps.add-comment.outputs.comment-repo }} + comment_url: ${{ steps.add-comment.outputs.comment-url }} steps: - name: Checkout actions folder uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 @@ -69,6 +77,19 @@ jobs: setupGlobals(core, github, context, exec, io); const { main } = require('/opt/gh-aw/actions/check_workflow_timestamp_api.cjs'); await main(); + - name: Add comment with workflow run link + id: add-comment + if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + env: + GH_AW_WORKFLOW_NAME: "Smoke Project" + GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e ๐Ÿงช *Project smoke test report by [{workflow_name}]({run_url})*\",\"appendOnlyComments\":true,\"runStarted\":\"๐Ÿงช [{workflow_name}]({run_url}) is now testing project operations...\",\"runSuccess\":\"โœ… [{workflow_name}]({run_url}) completed successfully. All project operations validated.\",\"runFailure\":\"โŒ [{workflow_name}]({run_url}) encountered failures. Check the logs for details.\"}" + 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/add_workflow_run_comment.cjs'); + await main(); agent: needs: activation @@ -78,8 +99,6 @@ jobs: contents: read issues: read pull-requests: read - concurrency: - group: "gh-aw-codex-${{ github.workflow }}" env: DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} GH_AW_ASSETS_ALLOWED_EXTS: "" @@ -138,19 +157,13 @@ jobs: setupGlobals(core, github, context, exec, io); const { main } = require('/opt/gh-aw/actions/checkout_pr_branch.cjs'); await main(); - - name: Validate CODEX_API_KEY or OPENAI_API_KEY secret + - name: Validate COPILOT_GITHUB_TOKEN secret id: validate-secret - run: /opt/gh-aw/actions/validate_multi_secret.sh CODEX_API_KEY OPENAI_API_KEY Codex https://github.github.com/gh-aw/reference/engines/#openai-codex + 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: - CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }} - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - - name: Setup Node.js - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 - with: - node-version: '24' - package-manager-cache: false - - name: Install Codex - run: npm install -g --silent @openai/codex@0.98.0 + 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 @@ -171,10 +184,149 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs cat > /opt/gh-aw/safeoutputs/config.json << 'EOF' - {"create_project_status_update":{"max":1},"missing_data":{},"missing_tool":{},"noop":{"max":1},"update_project":{"max":20}} + {"add_comment":{"max":2},"add_labels":{"allowed":["smoke-project"],"max":3},"create_issue":{"expires":2,"group":true,"max":1},"create_project_status_update":{"max":1},"create_pull_request":{},"missing_data":{},"missing_tool":{},"noop":{"max":1},"remove_labels":{"allowed":["smoke-project"],"max":3},"update_project":{"max":20}} 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.", + "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 2 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": "Create a new GitHub pull request to propose code changes. Use this after making file edits to submit them for review and merging. The PR will be created from the current branch with your committed changes. For code review comments on an existing PR, use create_pull_request_review_comment instead. CONSTRAINTS: Maximum 1 pull request(s) can be created. Title will be prefixed with \"[smoke-project] \".", + "inputSchema": { + "additionalProperties": false, + "properties": { + "body": { + "description": "Detailed PR description in Markdown. Include what changes were made, why, testing notes, and any breaking changes. Do NOT repeat the title as a heading.", + "type": "string" + }, + "branch": { + "description": "Source branch name containing the changes. If omitted, uses the current working branch.", + "type": "string" + }, + "labels": { + "description": "Labels to categorize the PR (e.g., 'enhancement', 'bugfix'). Labels must exist in the repository.", + "items": { + "type": "string" + }, + "type": "array" + }, + "title": { + "description": "Concise PR title describing the changes. Follow repository conventions (e.g., conventional commits). The title appears as the main heading.", + "type": "string" + } + }, + "required": [ + "title", + "body" + ], + "type": "object" + }, + "name": "create_pull_request" + }, + { + "description": "Add labels to an existing GitHub issue or pull request for categorization and filtering. Labels must already exist in the repository. For creating new issues with labels, use create_issue with the labels property instead. CONSTRAINTS: Only these labels are allowed: [smoke-project].", + "inputSchema": { + "additionalProperties": false, + "properties": { + "item_number": { + "description": "Issue or PR number to add labels to. This is the numeric ID from the GitHub URL (e.g., 456 in github.com/owner/repo/issues/456). If omitted, adds labels to the item that triggered this workflow.", + "type": "number" + }, + "labels": { + "description": "Label names to add (e.g., ['bug', 'priority-high']). Labels must exist in the repository.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "name": "add_labels" + }, + { + "description": "Remove labels from an existing GitHub issue or pull request. Silently skips labels that don't exist on the item. Use this to clean up labels or manage label lifecycles (e.g., removing 'needs-review' after review is complete). CONSTRAINTS: Only these labels can be removed: [smoke-project].", + "inputSchema": { + "additionalProperties": false, + "properties": { + "item_number": { + "description": "Issue or PR number to remove labels from. This is the numeric ID from the GitHub URL (e.g., 456 in github.com/owner/repo/issues/456). If omitted, removes labels from the item that triggered this workflow.", + "type": "number" + }, + "labels": { + "description": "Label names to remove (e.g., ['smoke', 'needs-triage']). Non-existent labels are silently skipped.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "labels" + ], + "type": "object" + }, + "name": "remove_labels" + }, { "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": { @@ -415,6 +567,68 @@ jobs: 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 + } + } + }, + "add_labels": { + "defaultMax": 5, + "fields": { + "item_number": { + "issueOrPRNumber": true + }, + "labels": { + "required": true, + "type": "array", + "itemType": "string", + "itemSanitize": true, + "itemMaxLength": 128 + } + } + }, + "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": { @@ -454,6 +668,35 @@ jobs: } } }, + "create_pull_request": { + "defaultMax": 1, + "fields": { + "body": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "branch": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 256 + }, + "labels": { + "type": "array", + "itemType": "string", + "itemSanitize": true, + "itemMaxLength": 128 + }, + "title": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 128 + } + } + }, "missing_tool": { "defaultMax": 20, "fields": { @@ -570,118 +813,12 @@ jobs: bash /opt/gh-aw/actions/start_safe_outputs_server.sh - - name: Setup Safe Inputs Config - run: | - mkdir -p /opt/gh-aw/safe-inputs/logs - cat > /opt/gh-aw/safe-inputs/tools.json << 'EOF_TOOLS_JSON' - { - "serverName": "safeinputs", - "version": "1.0.0", - "logDir": "/opt/gh-aw/safe-inputs/logs", - "tools": [ - { - "name": "gh", - "description": "Execute any gh CLI command. This tool is accessible as 'safeinputs-gh'. Provide the full command after 'gh' (e.g., args: 'pr list --limit 5'). The tool will run: gh \u003cargs\u003e. Use single quotes ' for complex args to avoid shell interpretation issues.", - "inputSchema": { - "properties": { - "args": { - "description": "Arguments to pass to gh CLI (without the 'gh' prefix). Examples: 'pr list --limit 5', 'issue view 123', 'api repos/{owner}/{repo}'", - "type": "string" - } - }, - "required": [ - "args" - ], - "type": "object" - }, - "handler": "gh.sh", - "env": { - "GH_AW_GH_TOKEN": "GH_AW_GH_TOKEN", - "GH_DEBUG": "GH_DEBUG" - }, - "timeout": 60 - } - ] - } - EOF_TOOLS_JSON - cat > /opt/gh-aw/safe-inputs/mcp-server.cjs << 'EOFSI' - const path = require("path"); - const { startHttpServer } = require("./safe_inputs_mcp_server_http.cjs"); - const configPath = path.join(__dirname, "tools.json"); - const port = parseInt(process.env.GH_AW_SAFE_INPUTS_PORT || "3000", 10); - const apiKey = process.env.GH_AW_SAFE_INPUTS_API_KEY || ""; - startHttpServer(configPath, { - port: port, - stateless: true, - logDir: "/opt/gh-aw/safe-inputs/logs" - }).catch(error => { - console.error("Failed to start safe-inputs HTTP server:", error); - process.exit(1); - }); - EOFSI - chmod +x /opt/gh-aw/safe-inputs/mcp-server.cjs - - - name: Setup Safe Inputs Tool Files - run: | - cat > /opt/gh-aw/safe-inputs/gh.sh << 'EOFSH_gh' - #!/bin/bash - # Auto-generated safe-input tool: gh - # Execute any gh CLI command. This tool is accessible as 'safeinputs-gh'. Provide the full command after 'gh' (e.g., args: 'pr list --limit 5'). The tool will run: gh . Use single quotes ' for complex args to avoid shell interpretation issues. - - set -euo pipefail - - echo "gh $INPUT_ARGS" - echo " token: ${GH_AW_GH_TOKEN:0:6}..." - GH_TOKEN="$GH_AW_GH_TOKEN" gh $INPUT_ARGS - - EOFSH_gh - chmod +x /opt/gh-aw/safe-inputs/gh.sh - - - name: Generate Safe Inputs MCP Server Config - id: safe-inputs-config - run: | - # Generate a secure random API key (360 bits of entropy, 40+ chars) - API_KEY="" - API_KEY=$(openssl rand -base64 45 | tr -d '/+=') - PORT=3000 - - # Register API key as secret to mask it from logs - echo "::add-mask::${API_KEY}" - - # Set outputs for next steps - { - echo "safe_inputs_api_key=${API_KEY}" - echo "safe_inputs_port=${PORT}" - } >> "$GITHUB_OUTPUT" - - echo "Safe Inputs MCP server will run on port ${PORT}" - - - name: Start Safe Inputs MCP HTTP Server - id: safe-inputs-start - env: - DEBUG: '*' - GH_AW_SAFE_INPUTS_PORT: ${{ steps.safe-inputs-config.outputs.safe_inputs_port }} - GH_AW_SAFE_INPUTS_API_KEY: ${{ steps.safe-inputs-config.outputs.safe_inputs_api_key }} - GH_AW_GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_DEBUG: 1 - run: | - # Environment variables are set above to prevent template injection - export DEBUG - export GH_AW_SAFE_INPUTS_PORT - export GH_AW_SAFE_INPUTS_API_KEY - - bash /opt/gh-aw/actions/start_safe_inputs_server.sh - - name: Start MCP gateway id: start-mcp-gateway env: - GH_AW_GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_AW_SAFE_INPUTS_API_KEY: ${{ steps.safe-inputs-start.outputs.api_key }} - GH_AW_SAFE_INPUTS_PORT: ${{ steps.safe-inputs-start.outputs.port }} 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 }} - GH_DEBUG: 1 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: | @@ -700,63 +837,28 @@ jobs: # Register API key as secret to mask it from logs echo "::add-mask::${MCP_GATEWAY_API_KEY}" - export GH_AW_ENGINE="codex" - 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_INPUTS_PORT -e GH_AW_SAFE_INPUTS_API_KEY -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -e GH_AW_GH_TOKEN -e GH_DEBUG -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.103' - - cat > /tmp/gh-aw/mcp-config/config.toml << EOF - [history] - persistence = "none" - - [shell_environment_policy] - inherit = "core" - include_only = ["CODEX_API_KEY", "GH_AW_ASSETS_ALLOWED_EXTS", "GH_AW_ASSETS_BRANCH", "GH_AW_ASSETS_MAX_SIZE_KB", "GH_AW_SAFE_OUTPUTS", "GITHUB_PERSONAL_ACCESS_TOKEN", "GITHUB_REPOSITORY", "GITHUB_SERVER_URL", "HOME", "OPENAI_API_KEY", "PATH"] - - [mcp_servers.github] - user_agent = "smoke-project" - startup_timeout_sec = 120 - tool_timeout_sec = 60 - container = "ghcr.io/github/github-mcp-server:v0.30.3" - env = { "GITHUB_PERSONAL_ACCESS_TOKEN" = "$GH_AW_GITHUB_TOKEN", "GITHUB_READ_ONLY" = "1", "GITHUB_TOOLSETS" = "context,repos,issues,pull_requests" } - env_vars = ["GITHUB_PERSONAL_ACCESS_TOKEN", "GITHUB_READ_ONLY", "GITHUB_TOOLSETS"] - - [mcp_servers.safeinputs] - type = "http" - url = "http://host.docker.internal:$GH_AW_SAFE_INPUTS_PORT" - headers = { Authorization = "$GH_AW_SAFE_INPUTS_API_KEY" } + 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.103' - [mcp_servers.safeoutputs] - type = "http" - url = "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT" - - [mcp_servers.safeoutputs.headers] - Authorization = "$GH_AW_SAFE_OUTPUTS_API_KEY" - EOF - - # Generate JSON config for MCP gateway + 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_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}", "GITHUB_READ_ONLY": "1", "GITHUB_TOOLSETS": "context,repos,issues,pull_requests" } }, - "safeinputs": { - "type": "http", - "url": "http://host.docker.internal:$GH_AW_SAFE_INPUTS_PORT", - "headers": { - "Authorization": "$GH_AW_SAFE_INPUTS_API_KEY" - } - }, "safeoutputs": { "type": "http", "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT", "headers": { - "Authorization": "$GH_AW_SAFE_OUTPUTS_API_KEY" + "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}" } } }, @@ -776,11 +878,11 @@ jobs: const fs = require('fs'); const awInfo = { - engine_id: "codex", - engine_name: "Codex", - model: process.env.GH_AW_MODEL_AGENT_CODEX || "", + engine_id: "copilot", + engine_name: "GitHub Copilot CLI", + model: process.env.GH_AW_MODEL_AGENT_COPILOT || "", version: "", - agent_version: "0.98.0", + agent_version: "0.0.405", workflow_name: "Smoke Project", experimental: false, supports_tools_allowlist: true, @@ -829,7 +931,6 @@ jobs: 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 @@ -887,15 +988,6 @@ jobs: 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/shared/gh.md}} - PROMPT_EOF - cat << 'PROMPT_EOF' >> "$GH_AW_PROMPT" - {{#runtime-import .github/workflows/shared/reporting.md}} - PROMPT_EOF - cat << 'PROMPT_EOF' >> "$GH_AW_PROMPT" {{#runtime-import .github/workflows/smoke-project.md}} PROMPT_EOF - name: Substitute placeholders @@ -909,7 +1001,6 @@ jobs: 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: | @@ -926,7 +1017,6 @@ jobs: 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 } }); @@ -934,9 +1024,6 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 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'); @@ -951,24 +1038,44 @@ jobs: env: GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt run: bash /opt/gh-aw/actions/print_prompt_summary.sh - - name: Run Codex + - name: Execute GitHub Copilot CLI + id: agentic_execution + # Copilot CLI tool arguments (sorted): + timeout-minutes: 15 run: | set -o pipefail - mkdir -p "$CODEX_HOME/logs" - sudo -E awf --enable-chroot --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains '*.githubusercontent.com,*.jsr.io,172.30.0.1,api.npms.io,api.openai.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,bun.sh,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,deb.nodesource.com,deno.land,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,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,openai.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.npmjs.com,www.npmjs.org,yarnpkg.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.13.12 --skip-pull \ - -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && INSTRUCTION="$(cat /tmp/gh-aw/aw-prompts/prompt.txt)" && codex ${GH_AW_MODEL_AGENT_CODEX:+-c model="$GH_AW_MODEL_AGENT_CODEX" }exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check "$INSTRUCTION"' \ + sudo -E awf --enable-chroot --env-all --container-workdir "${GITHUB_WORKSPACE}" --allow-domains '*.githubusercontent.com,*.jsr.io,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,bun.sh,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,deb.nodesource.com,deno.land,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,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.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.npmjs.com,www.npmjs.org,yarnpkg.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: - CODEX_API_KEY: ${{ secrets.CODEX_API_KEY || secrets.OPENAI_API_KEY }} - CODEX_HOME: /tmp/gh-aw/mcp-config - GH_AW_MCP_CONFIG: /tmp/gh-aw/mcp-config/config.toml - GH_AW_MODEL_AGENT_CODEX: ${{ vars.GH_AW_MODEL_AGENT_CODEX || '' }} + 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 }} - GH_DEBUG: 1 + GITHUB_HEAD_REF: ${{ github.head_ref }} + GITHUB_REF_NAME: ${{ github.ref_name }} GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }} - OPENAI_API_KEY: ${{ secrets.CODEX_API_KEY || secrets.OPENAI_API_KEY }} - RUST_LOG: trace,hyper_util=info,mio=info,reqwest=info,os_info=info,codex_otel=warn,codex_core=debug,ocodex_exec=debug + GITHUB_WORKSPACE: ${{ github.workspace }} + XDG_CONFIG_HOME: /home/runner + - 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 @@ -988,12 +1095,11 @@ jobs: const { main } = require('/opt/gh-aw/actions/redact_secrets.cjs'); await main(); env: - GH_AW_SECRET_NAMES: 'CODEX_API_KEY,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN,OPENAI_API_KEY' - SECRET_CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }} + 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 }} - SECRET_OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - name: Upload Safe Outputs if: always() uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 @@ -1006,7 +1112,7 @@ jobs: uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 env: GH_AW_SAFE_OUTPUTS: ${{ env.GH_AW_SAFE_OUTPUTS }} - GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.jsr.io,172.30.0.1,api.npms.io,api.openai.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,bun.sh,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,deb.nodesource.com,deno.land,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,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,openai.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.npmjs.com,www.npmjs.org,yarnpkg.com" + GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,*.jsr.io,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.npms.io,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,bun.sh,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,deb.nodesource.com,deno.land,get.pnpm.io,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,jsr.io,keyserver.ubuntu.com,lfs.github.com,nodejs.org,npm.pkg.github.com,npmjs.com,npmjs.org,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.bower.io,registry.npmjs.com,registry.npmjs.org,registry.yarnpkg.com,repo.yarnpkg.com,s.symcb.com,s.symcd.com,security.ubuntu.com,skimdb.npmjs.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.npmjs.com,www.npmjs.org,yarnpkg.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} with: @@ -1027,28 +1133,19 @@ jobs: with: name: agent_outputs path: | - /tmp/gh-aw/mcp-config/logs/ + /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.0.0 env: - GH_AW_AGENT_OUTPUT: /tmp/gh-aw/agent-stdio.log + 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_codex_log.cjs'); - await main(); - - name: Parse safe-inputs logs for step summary - if: always() - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 - 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_safe_inputs_logs.cjs'); + const { main } = require('/opt/gh-aw/actions/parse_copilot_log.cjs'); await main(); - name: Parse MCP gateway logs for step summary if: always() @@ -1079,10 +1176,10 @@ jobs: /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/aw_info.json /tmp/gh-aw/mcp-logs/ - /tmp/gh-aw/safe-inputs/logs/ /tmp/gh-aw/sandbox/firewall/logs/ /tmp/gh-aw/agent-stdio.log /tmp/gh-aw/agent/ + /tmp/gh-aw/aw.patch if-no-files-found: ignore conclusion: @@ -1180,6 +1277,20 @@ jobs: setupGlobals(core, github, context, exec, io); const { main } = require('/opt/gh-aw/actions/handle_agent_failure.cjs'); await main(); + - name: Handle Create Pull Request Error + id: handle_create_pr_error + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + env: + GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} + GH_AW_WORKFLOW_NAME: "Smoke Project" + GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + 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_create_pr_error.cjs'); + await main(); - name: Update reaction comment with completion status id: conclusion uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 @@ -1205,8 +1316,6 @@ jobs: if: needs.agent.outputs.output_types != '' || needs.agent.outputs.has_patch == 'true' runs-on: ubuntu-latest permissions: {} - concurrency: - group: "gh-aw-codex-${{ github.workflow }}" timeout-minutes: 10 outputs: success: ${{ steps.parse_results.outputs.success }} @@ -1254,34 +1363,42 @@ jobs: run: | mkdir -p /tmp/gh-aw/threat-detection touch /tmp/gh-aw/threat-detection/detection.log - - name: Validate CODEX_API_KEY or OPENAI_API_KEY secret + - name: Validate COPILOT_GITHUB_TOKEN secret id: validate-secret - run: /opt/gh-aw/actions/validate_multi_secret.sh CODEX_API_KEY OPENAI_API_KEY Codex https://github.github.com/gh-aw/reference/engines/#openai-codex + 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: - CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }} - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - - name: Setup Node.js - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 - with: - node-version: '24' - package-manager-cache: false - - name: Install Codex - run: npm install -g --silent @openai/codex@0.98.0 - - name: Run Codex + 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 - INSTRUCTION="$(cat "$GH_AW_PROMPT")" - mkdir -p "$CODEX_HOME/logs" - codex ${GH_AW_MODEL_DETECTION_CODEX:+-c model="$GH_AW_MODEL_DETECTION_CODEX" }exec --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check "$INSTRUCTION" 2>&1 | tee /tmp/gh-aw/threat-detection/detection.log + 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: - CODEX_API_KEY: ${{ secrets.CODEX_API_KEY || secrets.OPENAI_API_KEY }} - CODEX_HOME: /tmp/gh-aw/mcp-config - GH_AW_MCP_CONFIG: /tmp/gh-aw/mcp-config/config.toml - GH_AW_MODEL_DETECTION_CODEX: ${{ vars.GH_AW_MODEL_DETECTION_CODEX || '' }} + 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 }} - OPENAI_API_KEY: ${{ secrets.CODEX_API_KEY || secrets.OPENAI_API_KEY }} - RUST_LOG: trace,hyper_util=info,mio=info,reqwest=info,os_info=info,codex_otel=warn,codex_core=debug,ocodex_exec=debug + GITHUB_WORKSPACE: ${{ github.workspace }} + XDG_CONFIG_HOME: /home/runner - name: Parse threat detection results id: parse_results uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 @@ -1299,17 +1416,70 @@ jobs: path: /tmp/gh-aw/threat-detection/detection.log if-no-files-found: ignore + pre_activation: + if: > + ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.id == github.repository_id)) && + ((github.event_name != 'pull_request') || ((github.event.action != 'labeled') || (github.event.label.name == 'smoke'))) + runs-on: ubuntu-slim + permissions: + contents: read + discussions: write + issues: write + pull-requests: write + outputs: + activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }} + steps: + - name: Checkout actions folder + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 + with: + sparse-checkout: | + actions + persist-credentials: false + - name: Setup Scripts + uses: ./actions/setup + with: + destination: /opt/gh-aw/actions + - name: Add eyes reaction for immediate feedback + id: react + if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.id == github.repository_id) + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + env: + GH_AW_REACTION: "eyes" + 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/add_reaction.cjs'); + await main(); + - name: Check team membership for workflow + id: check_membership + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + 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: + - activation - agent - detection if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (needs.detection.outputs.success == 'true') runs-on: ubuntu-slim permissions: - contents: read + contents: write + discussions: write + issues: write + pull-requests: write timeout-minutes: 15 env: - GH_AW_ENGINE_ID: "codex" + GH_AW_ENGINE_ID: "copilot" GH_AW_SAFE_OUTPUT_MESSAGES: "{\"footer\":\"\\u003e ๐Ÿงช *Project smoke test report by [{workflow_name}]({run_url})*\",\"appendOnlyComments\":true,\"runStarted\":\"๐Ÿงช [{workflow_name}]({run_url}) is now testing project operations...\",\"runSuccess\":\"โœ… [{workflow_name}]({run_url}) completed successfully. All project operations validated.\",\"runFailure\":\"โŒ [{workflow_name}]({run_url}) encountered failures. Check the logs for details.\"}" GH_AW_WORKFLOW_ID: "smoke-project" GH_AW_WORKFLOW_NAME: "Smoke Project" @@ -1341,13 +1511,39 @@ jobs: mkdir -p /tmp/gh-aw/safeoutputs/ find "/tmp/gh-aw/safeoutputs/" -type f -print echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/safeoutputs/agent_output.json" >> "$GITHUB_ENV" + - name: Download patch artifact + continue-on-error: true + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + with: + name: agent-artifacts + path: /tmp/gh-aw/ + - name: Checkout repository + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6 + with: + token: ${{ github.token }} + persist-credentials: false + fetch-depth: 1 + - name: Configure Git credentials + if: ((!cancelled()) && (needs.agent.result != 'skipped')) && (contains(needs.agent.outputs.output_types, 'create_pull_request')) + env: + REPO_NAME: ${{ github.repository }} + SERVER_URL: ${{ github.server_url }} + GIT_TOKEN: ${{ github.token }} + 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:${GIT_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git" + echo "Git configured with standard GitHub Actions identity" - name: Process Safe Outputs id: process_safe_outputs uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 env: GH_AW_AGENT_OUTPUT: ${{ env.GH_AW_AGENT_OUTPUT }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_project_status_update\":{\"github-token\":\"${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }}\",\"max\":1,\"project\":\"https://github.com/orgs/githubnext/projects/146\"},\"missing_data\":{},\"missing_tool\":{},\"update_project\":{\"github-token\":\"${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }}\",\"max\":20,\"project\":\"https://github.com/orgs/githubnext/projects/146\",\"views\":[{\"name\":\"Smoke Test Board\",\"layout\":\"board\",\"filter\":\"is:open\"},{\"name\":\"Smoke Test Table\",\"layout\":\"table\"}]}}" - GH_AW_PROJECT_URL: "https://github.com/orgs/githubnext/projects/146" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"hide_older_comments\":true,\"max\":2},\"add_labels\":{\"allowed\":[\"smoke-project\"]},\"create_issue\":{\"close_older_issues\":true,\"expires\":2,\"group\":true,\"max\":1},\"create_project_status_update\":{\"github-token\":\"${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }}\",\"max\":1,\"project\":\"https://github.com/orgs/github/projects/24068\"},\"create_pull_request\":{\"base_branch\":\"${{ github.ref_name }}\",\"if_no_changes\":\"warn\",\"max\":1,\"max_patch_size\":1024,\"title_prefix\":\"[smoke-project] \"},\"missing_data\":{},\"missing_tool\":{},\"remove_labels\":{\"allowed\":[\"smoke-project\"]},\"update_project\":{\"github-token\":\"${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }}\",\"max\":20,\"project\":\"https://github.com/orgs/github/projects/24068\",\"views\":[{\"name\":\"Smoke Test Board\",\"layout\":\"board\",\"filter\":\"is:open\"}]}}" + GH_AW_PROJECT_URL: "https://github.com/orgs/github/projects/24068" GH_AW_PROJECT_GITHUB_TOKEN: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} with: github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} diff --git a/.github/workflows/smoke-project.md b/.github/workflows/smoke-project.md index 9998d724938..9a5682455d7 100644 --- a/.github/workflows/smoke-project.md +++ b/.github/workflows/smoke-project.md @@ -1,23 +1,18 @@ --- +name: Smoke Project description: Smoke Project - Test project operations on: workflow_dispatch: #schedule: every 12h - #pull_request: - # types: [labeled] - # names: ["smoke"] - #reaction: "eyes" + pull_request: + types: [labeled] + names: ["smoke"] + reaction: "eyes" permissions: contents: read pull-requests: read issues: read actions: read -name: Smoke Project -engine: codex -imports: - - shared/mood.md - - shared/gh.md - - shared/reporting.md network: allowed: - defaults @@ -28,31 +23,31 @@ tools: bash: - "*" safe-outputs: - #add-comment: - # hide-older-comments: true - # max: 2 - # target-repo: github-agentic-workflows/demo-repository - #create-issue: - # expires: 2h - # group: true - # close-older-issues: true - #add-labels: - # allowed: [smoke-project] - #remove-labels: - # allowed: [smoke-project] + add-comment: + hide-older-comments: true + max: 2 + create-pull-request: + title-prefix: "[smoke-project] " + if-no-changes: "warn" + create-issue: + expires: 2h + group: true + close-older-issues: true + add-labels: + allowed: [smoke-project] + remove-labels: + allowed: [smoke-project] update-project: max: 20 - project: "https://github.com/orgs/githubnext/projects/146" + project: "https://github.com/orgs/github/projects/24068" views: - name: "Smoke Test Board" layout: board filter: "is:open" - - name: "Smoke Test Table" - layout: table github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} create-project-status-update: max: 1 - project: "https://github.com/orgs/githubnext/projects/146" + project: "https://github.com/orgs/github/projects/24068" github-token: ${{ secrets.GH_AW_PROJECT_GITHUB_TOKEN }} messages: append-only-comments: true @@ -66,56 +61,77 @@ strict: true # Smoke Test: Project Operations Validation -**IMPORTANT: Keep all outputs extremely short and concise. Use single-line responses where possible. No verbose explanations.** +Default status field for any created items: "Todo". +Do the following operations EXACTLY in this order. +Do not re-create draft items but use their returned temporary-ids for the update operations. ## Test Requirements -1. **Project Operations Testing**: Use project-related safe-output tools to validate multiple project features against the real project configured in the frontmatter. Steps: +1. **Add items**: Create items in the project using different content types: - a. **Draft Issue Creation**: Call `update_project` with: - - `project`: "https://github.com/orgs/githubnext/projects/146" + a. **Draft Issue Creation**: + Call `update_project` with: + - `project`: "https://github.com/orgs/github/projects/24068" - `content_type`: "draft_issue" - - `draft_title`: "Smoke Test Draft Issue - Run ${{ github.run_id }}" + - `draft_title`: "Test *draft issue* for `smoke-project`" - `draft_body`: "Test draft issue for smoke test validation" + - `temporary_id`: "draft-1" - `fields`: `{"Status": "Todo", "Priority": "High"}` - b. **Field Creation with New Fields**: Call `update_project` with draft issue including new custom fields: - - `project`: "https://github.com/orgs/githubnext/projects/146" - - `content_type`: "draft_issue" - - `draft_title`: "Smoke Test Draft Issue with Custom Fields - Run ${{ github.run_id }}" - - `fields`: `{"Status": "Todo", "Priority": "High", "Team": "Engineering", "Sprint": "Q1-2026"}` + b. **Issue Creation**: + Call `update_project` with: + - `project`: "https://github.com/orgs/github/projects/24068" + - `content_type`: "issue" + - `content_number`: 19 + - `fields`: `{"Status": "Todo", "Priority": "High"}` - c. **Field Update**: Call `update_project` again with the same draft issue to update fields: - - `project`: "https://github.com/orgs/githubnext/projects/146" + c. **PR Creation**: + Call `update_project` with: + - `project`: "https://github.com/orgs/github/projects/24068" + - `content_type`: "pull_request" + - `content_number`: 18 + - `fields`: `{"Status": "Todo", "Priority": "High"}` + +2. **Update items**: Update the created items to validate field updates: + + a. **Draft Issue Update**: + Call `update_project` with the draft issue you created (use the returned temporary-id) to change status to "In Progress": + - `project`: "https://github.com/orgs/github/projects/24068" - `content_type`: "draft_issue" - - `draft_title`: "Smoke Test Draft Issue - Run ${{ github.run_id }}" - - `fields`: `{"Status": "In Progress", "Priority": "Medium"}` - - d. **Project Status Update**: Call `create_project_status_update` with: - - `project`: "https://github.com/orgs/githubnext/projects/146" - - `body`: "Smoke test project status - Run ${{ github.run_id }}" - - `status`: "ON_TRACK" - - f. **Verification**: For each operation: - - Verify the safe-output message is properly formatted in the output file - - Confirm the project URL is explicitly included in each message - - Check that all field names and values are correctly structured - - Validate content_type is correctly set for each operation type + - `draft_issue_id`: The temporary-id returned from step 1a (e.g., "aw_abc123def456") + - `fields`: `{"Status": "In Progress"}` + + b. **Pull Request Update**: + Call `update_project` to update the pull request item to change status to "In Progress": + - `project`: "https://github.com/orgs/github/projects/24068" + - `content_type`: "pull_request" + - `content_number`: 18 + - `fields`: `{"Status": "In Progress"}` -## Output + c. **Issue Update**: + Call `update_project` to update the issue item to change status to "In Progress": + - `project`: "https://github.com/orgs/github/projects/24068" + - `content_type`: "issue" + - `content_number`: 19 + - `fields`: `{"Status": "In Progress"}` -1. **Create an issue** with a summary of the project smoke test run: - - Title: "Smoke Test: Project Operations - ${{ github.run_id }}" - - Body should include: - - Test results (โœ… or โŒ for each test) - - Overall status: PASS or FAIL - - Run URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - - Timestamp +3. **Project Status Update**: -2. Add a **very brief** comment (max 5-10 lines) to the current pull request with: - - Test results (โœ… or โŒ for each test) - - Overall status: PASS or FAIL + a. Create a markdown report summarizing all the operations performed. Keep it short but make it clear what worked and what didn't: + Example `body`: + ```md + ## Run Summary + - Run: [{workflow_name}]({run_url}) + - List of operations performed: + - [x] Created *draft issue* update with status "Todo" + - [ ] ... + ``` -If all tests pass: -- Use the `add_labels` safe-output tool to add the label `smoke-project` to the pull request -- Use the `remove_labels` safe-output tool to remove the label `smoke-project` from the pull request + b. Call `create_project_status_update` with the report from step 3a. + Required fields: + - `project`: "https://github.com/orgs/github/projects/24068" + - `body`: The markdown report created in step 3a + Optional fields: + - `status`: "ON_TRACK" | "AT_RISK" | "OFF_TRACK" | "COMPLETE" | "INACTIVE" + - `start_date`: Optional date in "YYYY-MM-DD" format (if you want to represent the run start) + - `target_date`: Optional date in "YYYY-MM-DD" format (if you want to represent the run target/end)