diff --git a/.github/workflows/mobile-scan.lock.yml b/.github/workflows/mobile-scan.lock.yml index a71bec9e418889..23d4822e27064b 100644 --- a/.github/workflows/mobile-scan.lock.yml +++ b/.github/workflows/mobile-scan.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"705293dc67f0708eb58d9c6e9843ae3ea36346e9e116286707fe0dcaccfbbda1","compiler_version":"v0.68.1","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.5"} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9"},{"repo":"actions/upload-artifact","sha":"bbbca2ddaa5d8feaa63e36b76fdaad77386f024f","version":"v7"},{"repo":"github/gh-aw-actions/setup","sha":"2fe53acc038ba01c3bbdc767d4b25df31ca5bdfc","version":"v0.68.1"}]} +# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"f77456f33b61a0a920cfcf29a2ff065f923c2d75ef2c2d46909816fd0df9776e","compiler_version":"v0.68.1","strict":true,"agent_id":"copilot","agent_model":"claude-sonnet-4.5"} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9"},{"repo":"actions/upload-artifact","sha":"bbbca2ddaa5d8feaa63e36b76fdaad77386f024f","version":"v7"},{"repo":"github/gh-aw-actions/setup","sha":"2fe53acc038ba01c3bbdc767d4b25df31ca5bdfc","version":"v0.68.1"}]} # ___ _ _ # / _ \ | | (_) # | |_| | __ _ ___ _ __ | |_ _ ___ @@ -22,7 +22,7 @@ # # For more information: https://github.github.com/gh-aw/introduction/overview/ # -# Daily scan of the runtime-extra-platforms pipeline for Apple mobile and Android failures. Investigates and proposes fixes. +# Daily scan of the runtime-extra-platforms pipeline for Apple mobile and Android failures. Fixes per-test failures via PR; files an actionable tracking issue otherwise. # # Secrets used: # - COPILOT_GITHUB_TOKEN @@ -44,7 +44,6 @@ # Custom actions used: # - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 -# - actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 # - actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 # - github/gh-aw-actions/setup@2fe53acc038ba01c3bbdc767d4b25df31ca5bdfc # v0.68.1 @@ -198,19 +197,19 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_4285ed15b837fbd0_EOF' + cat << 'GH_AW_PROMPT_5b32ebfb2ce4676c_EOF' - GH_AW_PROMPT_4285ed15b837fbd0_EOF + GH_AW_PROMPT_5b32ebfb2ce4676c_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md" cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md" cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md" - cat << 'GH_AW_PROMPT_4285ed15b837fbd0_EOF' + cat << 'GH_AW_PROMPT_5b32ebfb2ce4676c_EOF' - Tools: add_comment(max:5), create_issue(max:2), create_pull_request(max:2), missing_tool, missing_data, noop - GH_AW_PROMPT_4285ed15b837fbd0_EOF + Tools: create_issue(max:3), create_pull_request(max:5), missing_tool, missing_data, noop + GH_AW_PROMPT_5b32ebfb2ce4676c_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" - cat << 'GH_AW_PROMPT_4285ed15b837fbd0_EOF' + cat << 'GH_AW_PROMPT_5b32ebfb2ce4676c_EOF' The following GitHub context information is available for this workflow: @@ -243,12 +242,12 @@ jobs: - **Note**: If a branch you need is not in the list above and is not listed as an additional fetched ref, it has NOT been checked out. For private repositories you cannot fetch it without proper authentication. If the branch is required and not available, exit with an error and ask the user to add it to the `fetch:` option of the `checkout:` configuration (e.g., `fetch: ["refs/pulls/open/*"]` for all open PR refs, or `fetch: ["main", "feature/my-branch"]` for specific branches). - GH_AW_PROMPT_4285ed15b837fbd0_EOF + GH_AW_PROMPT_5b32ebfb2ce4676c_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_4285ed15b837fbd0_EOF' + cat << 'GH_AW_PROMPT_5b32ebfb2ce4676c_EOF' {{#runtime-import .github/workflows/mobile-scan.md}} - GH_AW_PROMPT_4285ed15b837fbd0_EOF + GH_AW_PROMPT_5b32ebfb2ce4676c_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 @@ -400,16 +399,13 @@ jobs: GH_HOST: github.com - name: Install AWF binary run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.18 - - name: Determine automatic lockdown mode for GitHub MCP Server - id: determine-automatic-lockdown - uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9 + - name: Parse integrity filter lists + id: parse-guard-vars env: - GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} - GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} - with: - script: | - const determineAutomaticLockdown = require('${{ runner.temp }}/gh-aw/actions/determine_automatic_lockdown.cjs'); - await determineAutomaticLockdown(github, context, core); + GH_AW_BLOCKED_USERS_VAR: ${{ vars.GH_AW_GITHUB_BLOCKED_USERS || '' }} + GH_AW_TRUSTED_USERS_VAR: ${{ vars.GH_AW_GITHUB_TRUSTED_USERS || '' }} + GH_AW_APPROVAL_LABELS_VAR: ${{ vars.GH_AW_GITHUB_APPROVAL_LABELS || '' }} + run: bash "${RUNNER_TEMP}/gh-aw/actions/parse_guard_list.sh" - name: Download container images run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.18 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.18 ghcr.io/github/gh-aw-firewall/squid:0.25.18 ghcr.io/github/gh-aw-mcpg:v0.2.17 ghcr.io/github/github-mcp-server:v0.32.0 node:lts-alpine - name: Write Safe Outputs Config @@ -417,41 +413,22 @@ jobs: mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" mkdir -p /tmp/gh-aw/safeoutputs mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs - cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_00abe6b02dd0d453_EOF' - {"add_comment":{"max":5,"target":"*"},"create_issue":{"labels":["agentic-workflows","untriaged"],"max":2},"create_pull_request":{"draft":true,"labels":["agentic-workflows"],"max":2,"max_patch_size":1024,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS"],"protected_files_policy":"fallback-to-issue","protected_path_prefixes":[".github/",".agents/"],"title_prefix":"[mobile] "},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} - GH_AW_SAFE_OUTPUTS_CONFIG_00abe6b02dd0d453_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_9c9d9c81bf97b513_EOF' + {"create_issue":{"labels":["agentic-workflows"],"max":3},"create_pull_request":{"allowed_files":["src/libraries/**/tests/**","src/libraries/Common/tests/**"],"draft":true,"labels":["agentic-workflows"],"max":5,"max_patch_size":1024,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS"],"protected_files_policy":"blocked","protected_path_prefixes":[".github/",".agents/"],"title_prefix":"[mobile] "},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}} + GH_AW_SAFE_OUTPUTS_CONFIG_9c9d9c81bf97b513_EOF - name: Write Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | { "description_suffixes": { - "add_comment": " CONSTRAINTS: Maximum 5 comment(s) can be added. Target: *.", - "create_issue": " CONSTRAINTS: Maximum 2 issue(s) can be created. Labels [\"agentic-workflows\" \"untriaged\"] will be automatically added.", - "create_pull_request": " CONSTRAINTS: Maximum 2 pull request(s) can be created. Title will be prefixed with \"[mobile] \". Labels [\"agentic-workflows\"] will be automatically added. PRs will be created as drafts." + "create_issue": " CONSTRAINTS: Maximum 3 issue(s) can be created. Labels [\"agentic-workflows\"] will be automatically added.", + "create_pull_request": " CONSTRAINTS: Maximum 5 pull request(s) can be created. Title will be prefixed with \"[mobile] \". Labels [\"agentic-workflows\"] will be automatically added. PRs will be created as drafts." }, "repo_params": {}, "dynamic_tools": [] } GH_AW_VALIDATION_JSON: | { - "add_comment": { - "defaultMax": 1, - "fields": { - "body": { - "required": true, - "type": "string", - "sanitize": true, - "maxLength": 65000 - }, - "item_number": { - "issueOrPRNumber": true - }, - "repo": { - "type": "string", - "maxLength": 256 - } - } - }, "create_issue": { "defaultMax": 1, "fields": { @@ -648,8 +625,6 @@ jobs: GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.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_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }} - GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }} GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} run: | set -eo pipefail @@ -670,7 +645,7 @@ jobs: 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 MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -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_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -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.2.17' mkdir -p /home/runner/.copilot - cat << GH_AW_MCP_CONFIG_bf684fc7da0b3d83_EOF | bash "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh" + cat << GH_AW_MCP_CONFIG_17f3452edca3354e_EOF | bash "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh" { "mcpServers": { "github": { @@ -684,8 +659,11 @@ jobs: }, "guard-policies": { "allow-only": { - "min-integrity": "$GITHUB_MCP_GUARD_MIN_INTEGRITY", - "repos": "$GITHUB_MCP_GUARD_REPOS" + "approval-labels": ${{ steps.parse-guard-vars.outputs.approval_labels }}, + "blocked-users": ${{ steps.parse-guard-vars.outputs.blocked_users }}, + "min-integrity": "approved", + "repos": "all", + "trusted-users": ${{ steps.parse-guard-vars.outputs.trusted_users }} } } }, @@ -711,7 +689,7 @@ jobs: "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}" } } - GH_AW_MCP_CONFIG_bf684fc7da0b3d83_EOF + GH_AW_MCP_CONFIG_17f3452edca3354e_EOF - name: Download activation artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -753,7 +731,6 @@ jobs: # --allow-tool shell(ls) # --allow-tool shell(mkdir) # --allow-tool shell(pwd) - # --allow-tool shell(pwsh) # --allow-tool shell(sed) # --allow-tool shell(sh) # --allow-tool shell(sort) @@ -773,7 +750,7 @@ jobs: (umask 177 && touch /tmp/gh-aw/agent-stdio.log) # shellcheck disable=SC1003 sudo -E awf --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --allow-domains '*.blob.core.windows.net,*.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,dev.azure.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,helix.dot.net,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,www.googleapis.com' --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --image-tag 0.25.18 --skip-pull --enable-api-proxy \ - -- /bin/bash -c 'node ${RUNNER_TEMP}/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-tool github --allow-tool safeoutputs --allow-tool '\''shell(awk)'\'' --allow-tool '\''shell(basename)'\'' --allow-tool '\''shell(bash)'\'' --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(chmod)'\'' --allow-tool '\''shell(curl:*)'\'' --allow-tool '\''shell(cut)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(dirname)'\'' --allow-tool '\''shell(dotnet:*)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(env)'\'' --allow-tool '\''shell(find)'\'' --allow-tool '\''shell(git add:*)'\'' --allow-tool '\''shell(git branch:*)'\'' --allow-tool '\''shell(git checkout:*)'\'' --allow-tool '\''shell(git commit:*)'\'' --allow-tool '\''shell(git merge:*)'\'' --allow-tool '\''shell(git rm:*)'\'' --allow-tool '\''shell(git status)'\'' --allow-tool '\''shell(git switch:*)'\'' --allow-tool '\''shell(git:*)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(mkdir)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(pwsh)'\'' --allow-tool '\''shell(sed)'\'' --allow-tool '\''shell(sh)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(tee)'\'' --allow-tool '\''shell(test)'\'' --allow-tool '\''shell(tr)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(xargs)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log + -- /bin/bash -c 'node ${RUNNER_TEMP}/gh-aw/actions/copilot_driver.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --allow-tool github --allow-tool safeoutputs --allow-tool '\''shell(awk)'\'' --allow-tool '\''shell(basename)'\'' --allow-tool '\''shell(bash)'\'' --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(chmod)'\'' --allow-tool '\''shell(curl:*)'\'' --allow-tool '\''shell(cut)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(dirname)'\'' --allow-tool '\''shell(dotnet:*)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(env)'\'' --allow-tool '\''shell(find)'\'' --allow-tool '\''shell(git add:*)'\'' --allow-tool '\''shell(git branch:*)'\'' --allow-tool '\''shell(git checkout:*)'\'' --allow-tool '\''shell(git commit:*)'\'' --allow-tool '\''shell(git merge:*)'\'' --allow-tool '\''shell(git rm:*)'\'' --allow-tool '\''shell(git status)'\'' --allow-tool '\''shell(git switch:*)'\'' --allow-tool '\''shell(git:*)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(jq)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(mkdir)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(sed)'\'' --allow-tool '\''shell(sh)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(tee)'\'' --allow-tool '\''shell(test)'\'' --allow-tool '\''shell(tr)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(xargs)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE COPILOT_GITHUB_TOKEN: ${{ case(needs.pre_activation.outputs.copilot_pat_number == '0', secrets.COPILOT_PAT_0, needs.pre_activation.outputs.copilot_pat_number == '1', secrets.COPILOT_PAT_1, needs.pre_activation.outputs.copilot_pat_number == '2', secrets.COPILOT_PAT_2, needs.pre_activation.outputs.copilot_pat_number == '3', secrets.COPILOT_PAT_3, needs.pre_activation.outputs.copilot_pat_number == '4', secrets.COPILOT_PAT_4, needs.pre_activation.outputs.copilot_pat_number == '5', secrets.COPILOT_PAT_5, needs.pre_activation.outputs.copilot_pat_number == '6', secrets.COPILOT_PAT_6, needs.pre_activation.outputs.copilot_pat_number == '7', secrets.COPILOT_PAT_7, needs.pre_activation.outputs.copilot_pat_number == '8', secrets.COPILOT_PAT_8, needs.pre_activation.outputs.copilot_pat_number == '9', secrets.COPILOT_PAT_9, secrets.COPILOT_GITHUB_TOKEN) }} @@ -940,6 +917,8 @@ jobs: /tmp/gh-aw/sandbox/agent/logs/ /tmp/gh-aw/redacted-urls.log /tmp/gh-aw/mcp-logs/ + /tmp/gh-aw/proxy-logs/ + !/tmp/gh-aw/proxy-logs/proxy-tls/ /tmp/gh-aw/agent_usage.json /tmp/gh-aw/agent-stdio.log /tmp/gh-aw/agent/ @@ -972,7 +951,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: write - discussions: write issues: write pull-requests: write concurrency: @@ -1160,7 +1138,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 env: WORKFLOW_NAME: "Mobile Platform Failure Scanner" - WORKFLOW_DESCRIPTION: "Daily scan of the runtime-extra-platforms pipeline for Apple mobile and Android failures. Investigates and proposes fixes." + WORKFLOW_DESCRIPTION: "Daily scan of the runtime-extra-platforms pipeline for Apple mobile and Android failures. Fixes per-test failures via PR; files an actionable tracking issue otherwise." HAS_PATCH: ${{ needs.agent.outputs.has_patch }} with: script: | @@ -1288,7 +1266,6 @@ jobs: runs-on: ubuntu-slim permissions: contents: write - discussions: write issues: write pull-requests: write timeout-minutes: 15 @@ -1302,8 +1279,6 @@ jobs: outputs: code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} - comment_id: ${{ steps.process_safe_outputs.outputs.comment_id }} - comment_url: ${{ steps.process_safe_outputs.outputs.comment_url }} create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }} create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }} created_issue_number: ${{ steps.process_safe_outputs.outputs.created_issue_number }} @@ -1379,7 +1354,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.blob.core.windows.net,*.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,dev.azure.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,helix.dot.net,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,www.googleapis.com" GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} - GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":5,\"target\":\"*\"},\"create_issue\":{\"labels\":[\"agentic-workflows\",\"untriaged\"],\"max\":2},\"create_pull_request\":{\"draft\":true,\"labels\":[\"agentic-workflows\"],\"max\":2,\"max_patch_size\":1024,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\"],\"protected_files_policy\":\"fallback-to-issue\",\"protected_path_prefixes\":[\".github/\",\".agents/\"],\"title_prefix\":\"[mobile] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_issue\":{\"labels\":[\"agentic-workflows\"],\"max\":3},\"create_pull_request\":{\"allowed_files\":[\"src/libraries/**/tests/**\",\"src/libraries/Common/tests/**\"],\"draft\":true,\"labels\":[\"agentic-workflows\"],\"max\":5,\"max_patch_size\":1024,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"AGENTS.md\"],\"protected_files_policy\":\"blocked\",\"protected_path_prefixes\":[\".github/\",\".agents/\"],\"title_prefix\":\"[mobile] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{}}" GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }} with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/mobile-scan.md b/.github/workflows/mobile-scan.md index c79faf47e7e959..3598c13b5a636e 100644 --- a/.github/workflows/mobile-scan.md +++ b/.github/workflows/mobile-scan.md @@ -1,6 +1,6 @@ --- name: "Mobile Platform Failure Scanner" -description: "Daily scan of the runtime-extra-platforms pipeline for Apple mobile and Android failures. Investigates and proposes fixes." +description: "Daily scan of the runtime-extra-platforms pipeline for Apple mobile and Android failures. Fixes per-test failures via PR; files an actionable tracking issue otherwise." permissions: contents: read @@ -70,8 +70,9 @@ concurrency: tools: github: toolsets: [pull_requests, repos, issues, search] + min-integrity: approved edit: - bash: ["dotnet", "git", "find", "ls", "cat", "grep", "head", "tail", "wc", "curl", "jq", "pwsh", "tee", "sed", "awk", "tr", "cut", "sort", "uniq", "xargs", "echo", "date", "mkdir", "test", "env", "basename", "dirname", "bash", "sh", "chmod"] + bash: ["dotnet", "git", "find", "ls", "cat", "grep", "head", "tail", "wc", "curl", "jq", "tee", "sed", "awk", "tr", "cut", "sort", "uniq", "xargs", "echo", "date", "mkdir", "test", "env", "basename", "dirname", "bash", "sh", "chmod"] checkout: fetch-depth: 50 @@ -80,15 +81,15 @@ safe-outputs: create-pull-request: title-prefix: "[mobile] " draft: true - max: 2 - protected-files: fallback-to-issue + max: 5 + protected-files: blocked + allowed-files: + - "src/libraries/**/tests/**" + - "src/libraries/Common/tests/**" labels: [agentic-workflows] create-issue: - max: 2 - labels: [agentic-workflows, untriaged] - add-comment: - max: 5 - target: "*" + max: 3 + labels: [agentic-workflows] timeout-minutes: 60 @@ -103,150 +104,57 @@ network: # Mobile Platform Failure Scanner -You scan the `runtime-extra-platforms` pipeline (AzDO definition 154, org `dnceng-public`, project `public`) for Apple mobile and Android failures on `main`, triage them, and propose fixes. - -**Data safety:** CI logs can contain user paths, environment variables with secrets, and authentication headers. Sanitize log excerpts before posting in PR descriptions, issue comments, or commit messages by redacting these elements. - -## Step 1: Load domain knowledge - -Read `.github/skills/mobile-platforms/SKILL.md` for mobile platform triage criteria. - -For deeper Helix investigation patterns (console log analysis, pass/fail comparison, machine-specific diagnosis, XHarness false failure detection), fetch and read the helix-investigation skill from arcade-skills: - -```bash -curl -sL "https://raw.githubusercontent.com/dotnet/arcade-skills/f866c30a5b58e76492c90fd089082eb5f7e81a87/plugins/dotnet-dnceng/skills/helix-investigation/SKILL.md" -o /tmp/gh-aw/agent/helix-investigation-skill.md -cat /tmp/gh-aw/agent/helix-investigation-skill.md -``` - -Use the helix-investigation workflow (especially Steps 3-6: console log download, failure pattern matching, pass/fail comparison, root cause categorization) when drilling into individual Helix work item failures in Step 5. - -## Step 2: Get the latest build ID - -**Important conventions for this workflow environment:** - -- Each shell tool call runs in a fresh subshell -- environment variables do NOT persist across calls. Store intermediate values in files under `/tmp/gh-aw/agent/`. -- Command substitution like `$(cat file)` and parameter expansion like `${var@P}` are blocked by the agent's shell guard. Instead: either write the full command to a script file and `bash` it, or use `xargs -I{}` to inject file contents. -- **The shell guard also blocks `-o` and `>` output redirection in direct curl/command calls.** Always use `| tee /path/to/file` instead of `-o file` or `> file` for saving output. -- OData query params that start with `$` (e.g. `$top`) must be URL-encoded as `%24top` in curl URLs to avoid the shell guard. - -```bash -mkdir -p /tmp/gh-aw/agent -curl -sL "https://dev.azure.com/dnceng-public/public/_apis/build/builds?definitions=154&branchName=refs/heads/main&statusFilter=completed&%24top=1&api-version=7.1" | tee /tmp/gh-aw/agent/build.json | jq -r '.value[0] | "id=\(.id) result=\(.result)"' -``` - -Then extract the build ID and result (use `tee` instead of `>`): - -```bash -jq -r '.value[0].id' /tmp/gh-aw/agent/build.json | tee /tmp/gh-aw/agent/build_id.txt -jq -r '.value[0].result' /tmp/gh-aw/agent/build.json | tee /tmp/gh-aw/agent/build_result.txt -``` - -If `build_result.txt` contains `succeeded`, stop -- nothing to fix. - -To use the build id in a later command, write a small script that reads the file and run it: - -```bash -cat > /tmp/gh-aw/agent/run-ci-analysis.sh <<'SH' -#!/bin/bash -set -e -BUILD_ID=$(cat /tmp/gh-aw/agent/build_id.txt) -pwsh .github/skills/ci-analysis/scripts/Get-CIStatus.ps1 -BuildId "$BUILD_ID" -ShowLogs > /tmp/gh-aw/agent/ci-analysis.txt 2>&1 -echo "ci-analysis.txt size: $(wc -c < /tmp/gh-aw/agent/ci-analysis.txt)" -SH -bash /tmp/gh-aw/agent/run-ci-analysis.sh -``` - -The script is run via `bash scriptpath` (which is allowed), so the `$(...)` inside the script file is not flagged by the top-level shell guard. - -## Step 3: Analyze failures with ci-analysis - -`ci-analysis.txt` was written by the Step 2 helper script. Extract the JSON summary: - -```bash -sed -n '/\[CI_ANALYSIS_SUMMARY\]/,/^$/p' /tmp/gh-aw/agent/ci-analysis.txt > /tmp/gh-aw/agent/ci-summary.json -head -c 4000 /tmp/gh-aw/agent/ci-summary.json -``` - -Parse the `[CI_ANALYSIS_SUMMARY]` JSON to get `errorCategory`, `errorSnippet`, and `helixWorkItems` per failed job. - -## Step 4: Filter to mobile failures - -From the ci-analysis output, keep only failures whose job names match mobile platforms: - -- Apple mobile: `ios`, `tvos`, `maccatalyst`, `ioslike`, `ioslikesimulator` -- Android: `android` - -Ignore failures in non-mobile jobs. If no mobile jobs failed, stop. - -## Step 5: Drill into Helix failures +Scan the latest completed build of the `runtime-extra-platforms` pipeline (AzDO definition `154`, org `dnceng-public`, project `public`, branch `main`) for Apple mobile and Android failures. Every actionable failure becomes either a draft PR (per-test fix) or a tracking issue (everything else). Read `.github/skills/mobile-platforms/SKILL.md` first for the pipeline layout, platform helpers, and code-path map. -**You MUST drill into Helix console logs before classifying any failure.** Follow the helix-investigation skill workflow (loaded in Step 1) for each failed mobile work item: +## Outcome -1. Enumerate Helix work items from ci-analysis output (job ID, work item name, exit code, machine) -2. Download console logs and test result files per the skill's Step 3 -3. Analyze failure patterns per the skill's Step 4 (XHarness exit codes, false failure detection, timeout signatures) -4. Compare passing vs failing runs per the skill's Step 5 for intermittent failures +For each failed mobile work item in the latest completed build: -**Network note:** The `/console` endpoint on `helix.dot.net` redirects to Azure Blob Storage (`helixr*.blob.core.windows.net`, allowed by the network policy). Pass `-L` to `curl` to follow the redirect. Use `| tee /path/to/file` to save output (the shell guard blocks `-o` and `>` redirection). For complex commands with `$(...)`, write them to a script file and run with `bash`. +- **Per-test platform incompatibility** → open a draft PR. Use a per-test attribute change: `[SkipOnPlatform(...)]`, a narrowed `[ConditionalFact]` predicate built from existing `PlatformDetection.*` helpers, or `[ActiveIssue("https://github.com/dotnet/runtime/issues/", TestPlatforms.)]` referencing an **existing** issue. Touch only files matching the `allowed-files` policy (`src/libraries/**/tests/**`, including test `.csproj`). +- **Anything else** — product regression, native crash, multi-assembly cluster, infrastructure (including queue exhaustion / dead-letter / device-lost) — file a tracking issue. The issue is the deliverable; do not paper over a product bug with `SkipOnPlatform`. Group all dead-letter / queue exhaustion / device-lost failures from one run into a single infrastructure issue. Before filing, `search_issues` for an open issue with the matching `area-Infrastructure` + `os-*` label and update its description in place rather than creating a duplicate. -Capture for each failure: (a) the failing test FQN, (b) the assertion or exception, (c) the platform/arch, (d) whether the same work item repeats across jobs/runs. +Do not emit `noop`. Either a PR or an issue must come out of every actionable failure. -## Step 6: Triage each failure +Cap: **5 PRs and 3 issues per run.** Group failures that share one fix into a single PR. Group failures with the same root cause into a single issue. -Before classifying, search for existing open PRs that already fix these failures: +## Data sources -``` -gh search prs "[mobile]" --repo dotnet/runtime --state open --limit 10 -``` +- AzDO REST: `https://dev.azure.com/dnceng-public/public/_apis/build/...` — list completed builds (definition 154, branch main), get a build's timeline, download per-job AzDO logs. Mobile job names match the regex `(ios|tvos|maccatalyst|android)` (case-insensitive). +- Helix REST: `https://helix.dot.net/api/jobs/{jobId}/workitems?api-version=2019-06-17` — Helix job IDs appear in AzDO logs as `Job on `. Each work item has `Name`, `State`, `ExitCode`, `ConsoleOutputUri`. Failed: `ExitCode != 0` or `State == "Failed"`. Console URIs containing `helix-workitem-deadletter` are dead-lettered (queue had no agent) and are pure infra — drop them. -Also search for PRs referencing the specific test name or library. If a fix PR already exists, reference it in your comment instead of creating a duplicate. +Look back through roughly the last 20 completed builds to compute a "first seen in scanned window" timestamp and occurrence count per `(work_item, queue)` signature. -Classify each mobile failure using the criteria from `.github/skills/mobile-platforms/SKILL.md` and the console log content you fetched: +Drill into one representative console log per signature to confirm the failure shape (`[FAIL]` markers, assertion text) before classifying. -1. **Known build error** (ci-analysis already matched it): add a comment on that issue with the new build link and the work item name. If the root cause has an actionable code fix, proceed to Step 7. If it is purely infrastructure, stop here for this failure. -2. **Infrastructure**: provisioning/timeout/device-lost/network/Helix agent errors. Report on an existing tracking issue (or create one) with labels `area-Infrastructure` + the mobile `os-*` label. Do not attempt a code fix. -3. **Code regression**: a test that was passing started failing after a recent commit on `main`. Start with `git log --oneline --since='3 days ago' -- ` and inspect diffs. If nothing matches, widen the window or check for intermittent patterns. -4. **Platform-unsupported test**: a test that depends on behavior mobile platforms cannot support (process spawning, dynamic code emit where AOT-only, filesystem semantics, desktop JIT). The test was previously passing only because the platform was not exercised. +## PR body -## Step 7: Apply auto-fixes (do not emit noop) +Four H2 sections, in this exact order: -You are authorized -- and expected -- to open a draft PR directly for the following well-bounded patterns. Do **not** emit `noop` or only file an issue for these; commit the minimal change and open a draft PR. +1. **Reasoning** — why the test fails on the affected mobile platforms; why the chosen attribute is the right fix. +2. **Impact on platforms** — bullet list of `(platform/arch + Helix queue + exit code)` per affected occurrence. +3. **Errors log** — sanitized excerpt from the Helix console log (the `[FAIL]` line, the assertion or exception, and the `Failed tests:` summary). Strip JWTs, bearer tokens, `ApplicationGatewayAffinity*=`, and per-user paths. +4. **First build it occurred** — first build (in the scanned window) where this signature appeared: build link, finish time, commit SHA, occurrences-in-window count. State explicitly that this is computed within the scanned window and may not be the true origin. -**Auto-fixable patterns:** +Branch from `origin/main`. Stage only the files you intend to change with `git add `; never `git add -A`. Verify with `git diff --name-only --cached` before committing. Labels: one or more `os-*` (`os-android`, `os-ios`, `os-tvos`, `os-maccatalyst`) plus the test's `area-*` label. -- **Platform-unsupported test**: add `[SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst | TestPlatforms.Android, "")]` to the specific `[Fact]`/`[Theory]`, or narrow an existing `[ConditionalFact]` predicate. Prefer per-test attributes over disabling the whole class. -- **Test that requires reflection/dynamic-code on AOT mobile**: guard with `[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsReflectionEmitSupported))]` or `IsNotBuiltWithAggressiveTrimming` as appropriate. -- **Flaky test with a clear retry/timing fix**: increase the timeout or add a retry only if the existing pattern in the same file already uses one; otherwise file an issue with `[ActiveIssue("https://github.com/dotnet/runtime/issues/NNN", TestPlatforms.)]` referencing a newly-created tracking issue. -- **Test project that should exclude a mobile TFM**: adjust `TargetFrameworks`, `TestRuntime`, or the `` in the `.csproj` to exclude the unsupported platform, matching conventions already used in sibling projects. +## Issue body -For each auto-fix: +Use this when a PR is not the right tool — product regression, native crash, multi-assembly cluster, infra requiring an owner. Same four sections as a PR (Reasoning, Impact on platforms, Errors log, First build it occurred), plus a fifth: -1. **Branch from `main`, not from the workflow branch.** The safe-outputs patch is computed as `branch HEAD vs main`, so if you branch from the current checkout you will inadvertently pull unrelated `.github/` diffs into the PR and trigger the protected-file fallback. Use: - ```bash - git fetch origin main - git switch -c mobile-fix- origin/main - ``` - Then make the edit. -2. **Touch only `src/` test files and their `.csproj`.** Never stage anything under `.github/`, `eng/`, `docs/`, `global.json`, or the repo root. Before committing, run `git diff --name-only --cached` and abort if any path starts with `.github/`. -3. Use `git add ` -- never `git add -A` or `git add .`. -4. Verify the edit syntactically with `grep`/`cat`. Do not attempt `./build.sh` -- it is too heavy for the agent and CI will validate. -5. Open a draft PR with title `[mobile] `. The PR body must include: the build link, the failing test name, the Helix job+work item, the console log excerpt (sanitized), and the rationale for the fix class. -6. **Set `labels` on the PR/issue** (pass them in the `create_pull_request` / `create_issue` safeoutputs call). Required labels: - - **One or more OS labels** matching the affected platforms: `os-ios`, `os-tvos`, `os-maccatalyst`, `os-android`. If a fix applies to all Apple mobile, include `os-ios`, `os-tvos`, `os-maccatalyst`. If it affects all mobile, also include `os-android`. - - **One `area-*` label** matching the test's library (e.g., `area-System.IO.Compression`, `area-System.Runtime.Loader`, `area-Infrastructure` for build/infra). Pick from the existing repo labels -- do not invent new ones. - - Optional architecture label (`arch-arm64`, `arch-x64`) only if the failure is architecture-specific. -7. Post a comment on any related existing issue linking the PR. +5. **Recommended action** — concrete next step: which area owner, which file likely needs the fix, or what investigation would localize the root cause. Reference any related PR or issue you found via `search_issues`. The issue must be actionable — a checkbox-ready task list, not just "FYI". -**Do NOT auto-fix (open a tracking issue instead):** +Same `os-*` and `area-*` labels. -- Native crashes (SIGSEGV/SIGBUS/SIGABRT) in the runtime itself. -- Failures in >3 unrelated test assemblies suggesting a product regression -- file one issue linking all failures and ping the area owners via label, not via @mention. -- Anything touching files under `protected-files` or `protected-path-prefixes` (safe-outputs will auto-fallback to an issue). +## Hard environment constraints -## Step 8: Submit +These look like permission errors but are physical: -If you found an existing fix PR in Step 6, add a comment on the tracking issue linking it instead of creating a duplicate. +- `curl` URLs containing `?` or `&` MUST be **single-quoted**. Double-quoted URLs trigger `Permission denied and could not request permission from user`. +- `>` and `-o` redirection at the agent's command line is blocked. Use `| tee /path/to/file`. +- `$(...)` and `${var@P}` are blocked at the command line. Compose values via `xargs -I{}` or by reading files inline. +- OData `$top` must be encoded as `%24top` in URLs. +- Bash allowlist: `dotnet`, `git`, `find`, `ls`, `cat`, `grep`, `head`, `tail`, `wc`, `curl`, `jq`, `tee`, `sed`, `awk`, `tr`, `cut`, `sort`, `uniq`, `xargs`, `echo`, `date`, `mkdir`, `test`, `env`, `basename`, `dirname`, `bash`, `sh`, `chmod`. No `gh`, no `pwsh`, no `python`. Each call runs in a fresh subshell — persist intermediate state to files under `/tmp/gh-aw/agent/` (just files; you do not need to author a helper script). -Only emit `noop` if, after Step 5 drill-down, the failure falls into none of the categories above **and** you have already filed or commented on an appropriate issue. A `noop` with "manual investigation required" is not acceptable -- in that case, file a tracking issue with the console log excerpt. +## Submit -If you learned something generalizable during investigation, add it as a comment on the relevant issue so the team can later fold it into `.github/skills/mobile-platforms/SKILL.md`. +Search existing issues and PRs (`search_issues`, `search_pull_requests`) before creating anything new — never duplicate. When using `search_pull_requests`, filter to `is:merged OR review:approved` so the integrity filter does not silently drop low-trust results. If an issue already tracks the failure, **prefer opening a PR that references it via `[ActiveIssue("https://github.com/dotnet/runtime/issues/")]`** rather than filing another issue. If `search_issues` returns no matches, proceed to file the issue.