From 0aaad1a27ea7450d7f25d9d6c16f46121e1329ec Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Tue, 18 Aug 2026 15:14:56 +0200 Subject: [PATCH 1/9] Run the Markdown Linter on markdownlint-cli2 instead of Super Linter The Markdown Linter workflow has never run. All 63 runs since 2026-05-22 ended in startup_failure, because it is the only workflow in the repository that references an action outside actions/* and github/*, and this repository restricts Actions to a selected list: patterns_allowed: dotnet/arcade/.github/workflows/*, peter-evans/create-pull-request@*, DavidAnson/markdownlint-cli2-action@* verified_allowed: false super-linter/super-linter is not on that list, so the run was rejected before any job started. This is the same failure that took out the markdownlint gate in #10636. Swap Super Linter for markdownlint-cli2, pinned to 0.23.1, the version bundled by DavidAnson/markdownlint-cli2-action@v24.1.0 that markdownlint.yml already runs on every pull request. The scheduled report and the pull request gate now apply the same rules from .markdownlint-cli2.jsonc, including its ignores, so the report cannot flag anything the gate would let through. Two more bugs fixed along the way: - The lint step no longer fails the job when it finds violations. Super Linter failed the job, which skipped the agent that was supposed to write the report, so the workflow could not have reported violations even if it had started. - Super Linter ran with VALIDATE_ALL_CODEBASE=false, which lints only files that differ from the default branch. On a scheduled run on main that is nothing. markdownlint-cli2 scans all 86 tracked Markdown files. Also drop the now-unused packages: read and statuses: write permissions, and the dead check-results step whose output no job consumed. The workflow keeps no source: field. It came from githubnext/agentics/workflows/markdown-linter.md@main, and relinking it would let gh aw update restore the blocked action and break the workflow again. Compiled with gh aw v0.86.0 using --action-mode release --action-tag 435186c5, matching the pins in the other lock files; .github/scripts/check_action_pins.py passes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/markdown-linter.lock.yml | 139 ++++++++------------- .github/workflows/markdown-linter.md | 69 +++++----- 2 files changed, 83 insertions(+), 125 deletions(-) diff --git a/.github/workflows/markdown-linter.lock.yml b/.github/workflows/markdown-linter.lock.yml index 8ec0730a07..3dddc78722 100644 --- a/.github/workflows/markdown-linter.lock.yml +++ b/.github/workflows/markdown-linter.lock.yml @@ -1,5 +1,5 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"d7f7857c30ceaa8d8c13687f82ed53be4f9674b1c477ab0faf498cf4f056fb22","body_hash":"ed3f1406f293f05f3f2ab01d7bff4688be36f7d1e7968ee6d049bee6c903d91d","compiler_version":"v0.86.0","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.78"}} -# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw/actions/setup","sha":"435186c5f2612c5f2609a475dccfea3d9834ee88","version":"435186c5f2612c5f2609a475dccfea3d9834ee88"},{"repo":"super-linter/super-linter","sha":"4ce20838b8ab83717e78138c5b3a1407148e0918","version":"v8.7.0"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44","digest":"sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44@sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44","digest":"sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44@sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44","digest":"sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44@sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.8","digest":"sha256:38bbea36cdb46a3c9d04d1db05e672966f5239b431a2022eb35881688e5721d8","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.8@sha256:38bbea36cdb46a3c9d04d1db05e672966f5239b431a2022eb35881688e5721d8"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196"},{"image":"ghcr.io/github/github-mcp-server:v1.8.0","digest":"sha256:d5a18c04b92714c309eb46a2305087e91a4dbd80420f6e462656699f95093520","pinned_image":"ghcr.io/github/github-mcp-server:v1.8.0@sha256:d5a18c04b92714c309eb46a2305087e91a4dbd80420f6e462656699f95093520"}]} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"e5346474b8c3a0a3bcdc1ab40ce2d5136aeee9bdf4a6a19f22dff64ffcb42903","body_hash":"ce3fce41565b039f15e30e571a0c992db664a5e85eac45bfe4c5550f5829cd6f","compiler_version":"v0.86.0","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.78"}} +# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw/actions/setup","sha":"435186c5f2612c5f2609a475dccfea3d9834ee88","version":"435186c5f2612c5f2609a475dccfea3d9834ee88"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44","digest":"sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44@sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44","digest":"sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44@sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44","digest":"sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44@sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.8","digest":"sha256:38bbea36cdb46a3c9d04d1db05e672966f5239b431a2022eb35881688e5721d8","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.8@sha256:38bbea36cdb46a3c9d04d1db05e672966f5239b431a2022eb35881688e5721d8"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196"},{"image":"ghcr.io/github/github-mcp-server:v1.8.0","digest":"sha256:d5a18c04b92714c309eb46a2305087e91a4dbd80420f6e462656699f95093520","pinned_image":"ghcr.io/github/github-mcp-server:v1.8.0@sha256:d5a18c04b92714c309eb46a2305087e91a4dbd80420f6e462656699f95093520"}]} # This file was automatically generated by gh-aw (v0.86.0). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # # ___ _ _ @@ -17,15 +17,13 @@ # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ # # -# To update this file, edit githubnext/agentics/workflows/markdown-linter.md@main and run: +# To update this file, edit the corresponding .md file and run: # gh aw compile # Not all edits will cause changes to this file. # # For more information: https://github.github.com/gh-aw/introduction/overview/ # -# Runs Markdown quality checks using Super Linter and creates issues for violations -# -# Source: githubnext/agentics/workflows/markdown-linter.md@main +# Runs Markdown quality checks using markdownlint-cli2 and creates issues for violations # # Resolved workflow manifest: # Imports: @@ -47,7 +45,6 @@ # - actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # - github/gh-aw/actions/setup@435186c5f2612c5f2609a475dccfea3d9834ee88 -# - super-linter/super-linter@4ce20838b8ab83717e78138c5b3a1407148e0918 # v8.7.0 # # Container images used: # - ghcr.io/github/gh-aw-firewall/agent:0.27.44@sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4 @@ -113,7 +110,6 @@ jobs: GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/markdown-linter.lock.yml@${{ github.ref }} GH_AW_INFO_VERSION: "1.0.78" GH_AW_INFO_AWF_VERSION: "v0.27.44" - GH_AW_INFO_BODY_MODIFIED: "false" GH_AW_INFO_ENGINE_ID: "copilot" - name: Generate agentic run info id: generate_aw_info @@ -133,8 +129,6 @@ jobs: GH_AW_INFO_AWF_VERSION: "v0.27.44" GH_AW_INFO_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" - GH_AW_INFO_FRONTMATTER_SOURCE: "githubnext/agentics/workflows/markdown-linter.md@main" - GH_AW_INFO_BODY_MODIFIED: "false" GH_AW_COMPILED_STRICT: "true" uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: @@ -399,7 +393,7 @@ jobs: agent: needs: - activation - - super_linter + - markdownlint if: needs.activation.outputs.daily_ai_credits_exceeded != 'true' runs-on: ubuntu-latest permissions: @@ -458,7 +452,6 @@ jobs: GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/markdown-linter.lock.yml@${{ github.ref }} GH_AW_INFO_VERSION: "1.0.78" GH_AW_INFO_AWF_VERSION: "v0.27.44" - GH_AW_INFO_BODY_MODIFIED: "false" GH_AW_INFO_ENGINE_ID: "copilot" - name: Set runtime paths id: set-runtime-paths @@ -499,10 +492,10 @@ jobs: GH_AW_CACHE_DIR: /tmp/gh-aw/cache-memory GH_AW_MIN_INTEGRITY: none run: bash "${RUNNER_TEMP}/gh-aw/actions/setup_cache_memory_git.sh" - - name: Download super-linter log + - name: Download markdownlint log uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: super-linter-log + name: markdownlint-log path: /tmp/gh-aw/ - name: Configure Git credentials @@ -1063,8 +1056,8 @@ jobs: - activation - agent - detection + - markdownlint - safe_outputs - - super_linter - update_cache_memory if: > always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' || @@ -1099,7 +1092,6 @@ jobs: GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/markdown-linter.lock.yml@${{ github.ref }} GH_AW_INFO_VERSION: "1.0.78" GH_AW_INFO_AWF_VERSION: "v0.27.44" - GH_AW_INFO_BODY_MODIFIED: "false" GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output @@ -1191,8 +1183,7 @@ jobs: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_NOOP_MAX: "1" GH_AW_WORKFLOW_NAME: "Markdown Linter" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/markdown-linter.md@main" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/main/workflows/markdown-linter.md" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/markdown-linter.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_NOOP_REPORT_AS_ISSUE: "false" @@ -1213,8 +1204,7 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "Markdown Linter" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/markdown-linter.md@main" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/main/workflows/markdown-linter.md" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/markdown-linter.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }} GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }} @@ -1232,8 +1222,7 @@ jobs: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_MISSING_TOOL_CREATE_ISSUE: "true" GH_AW_WORKFLOW_NAME: "Markdown Linter" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/markdown-linter.md@main" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/main/workflows/markdown-linter.md" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/markdown-linter.md" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1248,8 +1237,7 @@ jobs: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true" GH_AW_WORKFLOW_NAME: "Markdown Linter" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/markdown-linter.md@main" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/main/workflows/markdown-linter.md" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/markdown-linter.md" with: github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} script: | @@ -1264,8 +1252,7 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "Markdown Linter" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/markdown-linter.md@main" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/main/workflows/markdown-linter.md" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/markdown-linter.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} GH_AW_WORKFLOW_ID: "markdown-linter" @@ -1316,8 +1303,7 @@ jobs: env: GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} GH_AW_WORKFLOW_NAME: "Markdown Linter" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/markdown-linter.md@main" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/main/workflows/markdown-linter.md" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/markdown-linter.md" GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} GH_AW_REPORT_FAILED_JOBS: "true" with: @@ -1358,7 +1344,6 @@ jobs: GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/markdown-linter.lock.yml@${{ github.ref }} GH_AW_INFO_VERSION: "1.0.78" GH_AW_INFO_AWF_VERSION: "v0.27.44" - GH_AW_INFO_BODY_MODIFIED: "false" GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output @@ -1415,7 +1400,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: WORKFLOW_NAME: "Markdown Linter" - WORKFLOW_DESCRIPTION: "Runs Markdown quality checks using Super Linter and creates issues for violations" + WORKFLOW_DESCRIPTION: "Runs Markdown quality checks using markdownlint-cli2 and creates issues for violations" HAS_PATCH: ${{ needs.agent.outputs.has_patch }} GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" with: @@ -1577,6 +1562,41 @@ jobs: } } + markdownlint: + needs: activation + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Configure GH_HOST for enterprise compatibility + id: ghes-host-config + shell: bash + run: | # zizmor: ignore[github-env] - GITHUB_SERVER_URL is set by GitHub Actions, not user input. + # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct + # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op. + GH_HOST="${GITHUB_SERVER_URL#https://}" + GH_HOST="${GH_HOST#http://}" + echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV" + - name: Checkout repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Run markdownlint-cli2 + id: markdownlint + run: | + set +e + npx --yes markdownlint-cli2@0.23.1 "**/*.md" > markdownlint.log 2>&1 + status=$? + cat markdownlint.log + echo "markdownlint-cli2 exit code: $status (0 = clean, 1 = violations found)" + - name: Upload markdownlint log + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: markdownlint-log + path: markdownlint.log + retention-days: 7 + safe_outputs: needs: - activation @@ -1602,8 +1622,7 @@ jobs: GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }} GH_AW_WORKFLOW_ID: "markdown-linter" GH_AW_WORKFLOW_NAME: "Markdown Linter" - GH_AW_WORKFLOW_SOURCE: "githubnext/agentics/workflows/markdown-linter.md@main" - GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/githubnext/agentics/blob/main/workflows/markdown-linter.md" + GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/markdown-linter.md" 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 }} @@ -1630,7 +1649,6 @@ jobs: GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/markdown-linter.lock.yml@${{ github.ref }} GH_AW_INFO_VERSION: "1.0.78" GH_AW_INFO_AWF_VERSION: "v0.27.44" - GH_AW_INFO_BODY_MODIFIED: "false" GH_AW_INFO_ENGINE_ID: "copilot" - name: Download agent output artifact id: download-agent-output @@ -1682,60 +1700,6 @@ jobs: /tmp/gh-aw/temporary-id-map.json if-no-files-found: ignore - super_linter: - needs: activation - runs-on: ubuntu-latest - permissions: - contents: read - packages: read - statuses: write - steps: - - name: Configure GH_HOST for enterprise compatibility - id: ghes-host-config - shell: bash - run: | # zizmor: ignore[github-env] - GITHUB_SERVER_URL is set by GitHub Actions, not user input. - # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct - # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op. - GH_HOST="${GITHUB_SERVER_URL#https://}" - GH_HOST="${GH_HOST#http://}" - echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV" - - name: Checkout repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - persist-credentials: false - - name: Super-linter - id: super-linter - # zizmor: ignore[github_action_from_unverified_creator_used] - uses: super-linter/super-linter@4ce20838b8ab83717e78138c5b3a1407148e0918 # v8.7.0 - env: - CREATE_LOG_FILE: "true" - DEFAULT_BRANCH: main - ENABLE_GITHUB_ACTIONS_STEP_SUMMARY: "true" - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - LOG_FILE: super-linter.log - VALIDATE_ALL_CODEBASE: "false" - VALIDATE_MARKDOWN: "true" - - name: Check for linting issues - id: check-results - run: | - if [ -f "super-linter.log" ] && [ -s "super-linter.log" ]; then - if grep -qE "ERROR|WARN|FAIL" super-linter.log; then - echo "needs-linting=true" >> "$GITHUB_OUTPUT" - else - echo "needs-linting=false" >> "$GITHUB_OUTPUT" - fi - else - echo "needs-linting=false" >> "$GITHUB_OUTPUT" - fi - - name: Upload super-linter log - if: always() - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: super-linter-log - path: super-linter.log - retention-days: 7 - update_cache_memory: needs: - activation @@ -1762,7 +1726,6 @@ jobs: GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/markdown-linter.lock.yml@${{ github.ref }} GH_AW_INFO_VERSION: "1.0.78" GH_AW_INFO_AWF_VERSION: "v0.27.44" - GH_AW_INFO_BODY_MODIFIED: "false" GH_AW_INFO_ENGINE_ID: "copilot" - name: Download cache-memory artifact (default) id: download_cache_default diff --git a/.github/workflows/markdown-linter.md b/.github/workflows/markdown-linter.md index ac1fa90259..bd7e6c48bf 100644 --- a/.github/workflows/markdown-linter.md +++ b/.github/workflows/markdown-linter.md @@ -23,57 +23,48 @@ safe-outputs: noop: report-as-issue: false steps: -- name: Download super-linter log +- name: Download markdownlint log uses: actions/download-artifact@v8.0.1 with: - name: super-linter-log + name: markdownlint-log path: /tmp/gh-aw/ -description: Runs Markdown quality checks using Super Linter and creates issues for violations +description: Runs Markdown quality checks using markdownlint-cli2 and creates issues for violations jobs: - super_linter: + markdownlint: permissions: contents: read - packages: read - statuses: write runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v7.0.1 with: - fetch-depth: 0 persist-credentials: false - - env: - CREATE_LOG_FILE: "true" - DEFAULT_BRANCH: main - ENABLE_GITHUB_ACTIONS_STEP_SUMMARY: "true" - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - LOG_FILE: super-linter.log - VALIDATE_ALL_CODEBASE: "false" - VALIDATE_MARKDOWN: "true" - id: super-linter - name: Super-linter - uses: super-linter/super-linter@v8.7.0 - - id: check-results - name: Check for linting issues + - id: markdownlint + name: Run markdownlint-cli2 + # Pinned to the markdownlint-cli2 version bundled by + # DavidAnson/markdownlint-cli2-action@v24.1.0, which .github/workflows/markdownlint.yml + # runs on every pull request, so this scheduled report and the pull request gate apply + # exactly the same rules. Configuration comes from .markdownlint-cli2.jsonc in the repo + # root, including its "ignores" list. Bump this together with that action. run: | - if [ -f "super-linter.log" ] && [ -s "super-linter.log" ]; then - if grep -qE "ERROR|WARN|FAIL" super-linter.log; then - echo "needs-linting=true" >> "$GITHUB_OUTPUT" - else - echo "needs-linting=false" >> "$GITHUB_OUTPUT" - fi - else - echo "needs-linting=false" >> "$GITHUB_OUTPUT" - fi + set +e + npx --yes markdownlint-cli2@0.23.1 "**/*.md" > markdownlint.log 2>&1 + status=$? + cat markdownlint.log + echo "markdownlint-cli2 exit code: $status (0 = clean, 1 = violations found)" - if: always() - name: Upload super-linter log + name: Upload markdownlint log uses: actions/upload-artifact@v7.0.1 with: - name: super-linter-log - path: super-linter.log + name: markdownlint-log + path: markdownlint.log retention-days: 7 name: Markdown Linter -source: githubnext/agentics/workflows/markdown-linter.md@main +# Intentionally no "source:" field. This workflow started as +# githubnext/agentics/workflows/markdown-linter.md@main, but that version runs +# super-linter/super-linter, which this repository's Actions policy does not allow, so every +# run failed at startup. Re-linking it to upstream would let `gh aw update` restore the +# blocked action and break the workflow again. timeout-minutes: 15 tools: bash: @@ -83,7 +74,7 @@ tools: --- # Markdown Quality Report -You are an expert documentation quality analyst. Your task is to analyze the Super Linter Markdown output and create a comprehensive issue report for the repository maintainers. +You are an expert documentation quality analyst. Your task is to analyze the markdownlint-cli2 output and create a comprehensive issue report for the repository maintainers. ## Context @@ -93,12 +84,15 @@ You are an expert documentation quality analyst. Your task is to analyze the Sup ## Your Task -1. **Read the linter output** from `/tmp/gh-aw/super-linter.log` using the bash tool +1. **Read the linter output** from `/tmp/gh-aw/markdownlint.log` using the bash tool 2. **Analyze the findings**: - Categorize errors by severity (critical, high, medium, low) - Identify patterns in the errors - Determine which errors are most important to fix first - - Note: This workflow only validates Markdown files + - Note: This workflow only validates Markdown files, using the repository's + `.markdownlint-cli2.jsonc` rules. The same rules gate every pull request through + `.github/workflows/markdownlint.yml`, so anything reported here also blocks new pull + requests. Rules that file disables (for example MD013 line length) are not violations. 3. **Create a detailed issue** with the following structure: ### Issue Title @@ -149,7 +143,8 @@ Use format: "Markdown Quality Report - [Date] - [X] issues found" ## 🔗 References - [Link to workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) -- [Super Linter Documentation](https://github.com/super-linter/super-linter) +- [markdownlint-cli2 Documentation](https://github.com/DavidAnson/markdownlint-cli2) +- [markdownlint rule reference](https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md) ``` ## Important Guidelines From f996f969aeb7f0d9bcd631fa4758a877c44c9080 Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Wed, 19 Aug 2026 09:48:55 +0200 Subject: [PATCH 2/9] Fail the lint job when markdownlint-cli2 cannot run The step swallowed every exit code, so an npm or configuration failure looked the same as a clean run: the log held a stack trace instead of lint results, and the agent went on to report "no issues" over a run that never linted. markdownlint-cli2 exits 0 clean, 1 with violations, and 2 when it fails to run. Keep 0 and 1 green, because violations are what the agent reports on, and fail the job for anything above that. Also update the workflow catalog entry, which still described this workflow as running Super Linter. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/README.md | 2 +- .github/workflows/markdown-linter.lock.yml | 15 +++++++++++---- .github/workflows/markdown-linter.md | 13 ++++++++++--- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 7e4634ceb2..b6e500c515 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -257,7 +257,7 @@ a security control. | [`unskip-closed-tests.md`](./unskip-closed-tests.md) | Weekly + manual | Finds tests skipped via `[Ignore("…#issue")]` whose tracking issue is now closed, verifies they pass, and opens a PR re-enabling them. | | [`duplicate-code-detector.md`](./duplicate-code-detector.md) | Schedule + manual | Identifies duplicate code patterns and suggests refactoring opportunities. | | [`malicious-code-scan.md`](./malicious-code-scan.md) | Schedule + manual | Reviews code changes from the last 3 days for suspicious patterns indicating malicious or agentic threats. | -| [`markdown-linter.md`](./markdown-linter.md) | Schedule + manual + issues | Runs Markdown quality checks using Super Linter and opens issues for violations. | +| [`markdown-linter.md`](./markdown-linter.md) | Schedule + manual + issues | Runs Markdown quality checks using markdownlint-cli2 and opens issues for violations. | | [`link-checker.md`](./link-checker.md) | Daily | Daily automated link checker that finds and fixes broken links in documentation files. | | [`glossary-maintainer.md`](./glossary-maintainer.md) | Schedule + manual | Maintains and updates the documentation glossary based on codebase changes. | diff --git a/.github/workflows/markdown-linter.lock.yml b/.github/workflows/markdown-linter.lock.yml index 3dddc78722..75f00748b4 100644 --- a/.github/workflows/markdown-linter.lock.yml +++ b/.github/workflows/markdown-linter.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"e5346474b8c3a0a3bcdc1ab40ce2d5136aeee9bdf4a6a19f22dff64ffcb42903","body_hash":"ce3fce41565b039f15e30e571a0c992db664a5e85eac45bfe4c5550f5829cd6f","compiler_version":"v0.86.0","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.78"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"bdeaba19cd63d69cf206eaab68582e28835806bf71d20193a34acffb1f8d2eef","body_hash":"ce3fce41565b039f15e30e571a0c992db664a5e85eac45bfe4c5550f5829cd6f","compiler_version":"v0.86.0","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.78"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw/actions/setup","sha":"435186c5f2612c5f2609a475dccfea3d9834ee88","version":"435186c5f2612c5f2609a475dccfea3d9834ee88"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44","digest":"sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44@sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44","digest":"sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44@sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44","digest":"sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44@sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.8","digest":"sha256:38bbea36cdb46a3c9d04d1db05e672966f5239b431a2022eb35881688e5721d8","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.8@sha256:38bbea36cdb46a3c9d04d1db05e672966f5239b431a2022eb35881688e5721d8"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196"},{"image":"ghcr.io/github/github-mcp-server:v1.8.0","digest":"sha256:d5a18c04b92714c309eb46a2305087e91a4dbd80420f6e462656699f95093520","pinned_image":"ghcr.io/github/github-mcp-server:v1.8.0@sha256:d5a18c04b92714c309eb46a2305087e91a4dbd80420f6e462656699f95093520"}]} # This file was automatically generated by gh-aw (v0.86.0). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -1584,11 +1584,18 @@ jobs: - name: Run markdownlint-cli2 id: markdownlint run: | - set +e - npx --yes markdownlint-cli2@0.23.1 "**/*.md" > markdownlint.log 2>&1 - status=$? + status=0 + npx --yes markdownlint-cli2@0.23.1 "**/*.md" > markdownlint.log 2>&1 || status=$? cat markdownlint.log echo "markdownlint-cli2 exit code: $status (0 = clean, 1 = violations found)" + # Exit 1 means violations, which are what the agent reports on, so the job stays green. + # Anything above that is markdownlint-cli2 failing to run at all (2 = execution or + # configuration error). The log then holds a stack trace rather than lint results, so + # fail instead of letting the agent report "no issues" over a run that never linted. + if [ "$status" -gt 1 ]; then + echo "::error::markdownlint-cli2 could not complete (exit $status); see the log above." + exit "$status" + fi - name: Upload markdownlint log if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 diff --git a/.github/workflows/markdown-linter.md b/.github/workflows/markdown-linter.md index bd7e6c48bf..9cb655ccc6 100644 --- a/.github/workflows/markdown-linter.md +++ b/.github/workflows/markdown-linter.md @@ -47,11 +47,18 @@ jobs: # exactly the same rules. Configuration comes from .markdownlint-cli2.jsonc in the repo # root, including its "ignores" list. Bump this together with that action. run: | - set +e - npx --yes markdownlint-cli2@0.23.1 "**/*.md" > markdownlint.log 2>&1 - status=$? + status=0 + npx --yes markdownlint-cli2@0.23.1 "**/*.md" > markdownlint.log 2>&1 || status=$? cat markdownlint.log echo "markdownlint-cli2 exit code: $status (0 = clean, 1 = violations found)" + # Exit 1 means violations, which are what the agent reports on, so the job stays green. + # Anything above that is markdownlint-cli2 failing to run at all (2 = execution or + # configuration error). The log then holds a stack trace rather than lint results, so + # fail instead of letting the agent report "no issues" over a run that never linted. + if [ "$status" -gt 1 ]; then + echo "::error::markdownlint-cli2 could not complete (exit $status); see the log above." + exit "$status" + fi - if: always() name: Upload markdownlint log uses: actions/upload-artifact@v7.0.1 From c7b67486b2634bc94a93187a74ac56815a5e5d2e Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Mon, 24 Aug 2026 10:46:23 +0200 Subject: [PATCH 3/9] Install markdownlint-cli2 in its own step so npm failures fail the job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit npx exits 1 when it cannot resolve or download the package, which is the same code markdownlint-cli2 uses for "violations found". A registry outage therefore kept the job green and handed the agent an npm error log to report as if it were lint results — the misleading report this step was meant to prevent. Install the pinned version in a separate step, which fails the job on its own, and run the installed binary so the tolerated exit code 1 can only come from markdownlint-cli2 itself. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/markdown-linter.lock.yml | 6 ++++-- .github/workflows/markdown-linter.md | 16 +++++++++++----- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/markdown-linter.lock.yml b/.github/workflows/markdown-linter.lock.yml index 484c8adba0..4e4682580e 100644 --- a/.github/workflows/markdown-linter.lock.yml +++ b/.github/workflows/markdown-linter.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"bdeaba19cd63d69cf206eaab68582e28835806bf71d20193a34acffb1f8d2eef","body_hash":"ce3fce41565b039f15e30e571a0c992db664a5e85eac45bfe4c5550f5829cd6f","compiler_version":"v0.86.0","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.78"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"1b82076455c17e650505795a15b26f0b05619248de954488763ac2884c1d139d","body_hash":"ce3fce41565b039f15e30e571a0c992db664a5e85eac45bfe4c5550f5829cd6f","compiler_version":"v0.86.0","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.78"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw/actions/setup","sha":"48e5fa3ff52294d91d97715017a9f8693a48387f","version":"48e5fa3ff52294d91d97715017a9f8693a48387f"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44","digest":"sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44@sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44","digest":"sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44@sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44","digest":"sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44@sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.8","digest":"sha256:38bbea36cdb46a3c9d04d1db05e672966f5239b431a2022eb35881688e5721d8","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.8@sha256:38bbea36cdb46a3c9d04d1db05e672966f5239b431a2022eb35881688e5721d8"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196"},{"image":"ghcr.io/github/github-mcp-server:v1.8.0","digest":"sha256:d5a18c04b92714c309eb46a2305087e91a4dbd80420f6e462656699f95093520","pinned_image":"ghcr.io/github/github-mcp-server:v1.8.0@sha256:d5a18c04b92714c309eb46a2305087e91a4dbd80420f6e462656699f95093520"}]} # This file was automatically generated by gh-aw (v0.86.0). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -1581,11 +1581,13 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false + - name: Install markdownlint-cli2 + run: npm install --global markdownlint-cli2@0.23.1 - name: Run markdownlint-cli2 id: markdownlint run: | status=0 - npx --yes markdownlint-cli2@0.23.1 "**/*.md" > markdownlint.log 2>&1 || status=$? + markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? cat markdownlint.log echo "markdownlint-cli2 exit code: $status (0 = clean, 1 = violations found)" # Exit 1 means violations, which are what the agent reports on, so the job stays green. diff --git a/.github/workflows/markdown-linter.md b/.github/workflows/markdown-linter.md index 9cb655ccc6..b8e5f97f36 100644 --- a/.github/workflows/markdown-linter.md +++ b/.github/workflows/markdown-linter.md @@ -39,16 +39,22 @@ jobs: uses: actions/checkout@v7.0.1 with: persist-credentials: false - - id: markdownlint - name: Run markdownlint-cli2 + - name: Install markdownlint-cli2 # Pinned to the markdownlint-cli2 version bundled by # DavidAnson/markdownlint-cli2-action@v24.1.0, which .github/workflows/markdownlint.yml # runs on every pull request, so this scheduled report and the pull request gate apply - # exactly the same rules. Configuration comes from .markdownlint-cli2.jsonc in the repo - # root, including its "ignores" list. Bump this together with that action. + # exactly the same rules. Bump this together with that action. + # Installed in its own step so that a registry outage or a bad version fails the job + # here. npx exits 1 for those too, which the lint step below cannot tell apart from + # "violations found", and it would report an npm error log as if it were lint results. + run: npm install --global markdownlint-cli2@0.23.1 + - id: markdownlint + name: Run markdownlint-cli2 + # Configuration comes from .markdownlint-cli2.jsonc in the repo root, including its + # "ignores" list. run: | status=0 - npx --yes markdownlint-cli2@0.23.1 "**/*.md" > markdownlint.log 2>&1 || status=$? + markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? cat markdownlint.log echo "markdownlint-cli2 exit code: $status (0 = clean, 1 = violations found)" # Exit 1 means violations, which are what the agent reports on, so the job stays green. From 2d8e387ef009f0620ec4c88c9ae918913035988e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amaury=20Lev=C3=A9?= Date: Mon, 24 Aug 2026 13:17:03 +0200 Subject: [PATCH 4/9] Update markdownlint-cli2 to 0.23.2 Keep the scheduled workflow aligned with markdownlint-cli2-action v24.2.0 on main. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 021b7d71-92b8-40a1-a0ab-5a6d768c5b1a --- .github/workflows/markdown-linter.lock.yml | 4 ++-- .github/workflows/markdown-linter.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/markdown-linter.lock.yml b/.github/workflows/markdown-linter.lock.yml index 4e4682580e..a7d46b7451 100644 --- a/.github/workflows/markdown-linter.lock.yml +++ b/.github/workflows/markdown-linter.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"1b82076455c17e650505795a15b26f0b05619248de954488763ac2884c1d139d","body_hash":"ce3fce41565b039f15e30e571a0c992db664a5e85eac45bfe4c5550f5829cd6f","compiler_version":"v0.86.0","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.78"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"647c8866e4a19f4956953431af4683d06f3c95808f352f81d92582250750117b","body_hash":"ce3fce41565b039f15e30e571a0c992db664a5e85eac45bfe4c5550f5829cd6f","compiler_version":"v0.86.0","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.78"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw/actions/setup","sha":"48e5fa3ff52294d91d97715017a9f8693a48387f","version":"48e5fa3ff52294d91d97715017a9f8693a48387f"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44","digest":"sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44@sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44","digest":"sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44@sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44","digest":"sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44@sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.8","digest":"sha256:38bbea36cdb46a3c9d04d1db05e672966f5239b431a2022eb35881688e5721d8","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.8@sha256:38bbea36cdb46a3c9d04d1db05e672966f5239b431a2022eb35881688e5721d8"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196"},{"image":"ghcr.io/github/github-mcp-server:v1.8.0","digest":"sha256:d5a18c04b92714c309eb46a2305087e91a4dbd80420f6e462656699f95093520","pinned_image":"ghcr.io/github/github-mcp-server:v1.8.0@sha256:d5a18c04b92714c309eb46a2305087e91a4dbd80420f6e462656699f95093520"}]} # This file was automatically generated by gh-aw (v0.86.0). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -1582,7 +1582,7 @@ jobs: with: persist-credentials: false - name: Install markdownlint-cli2 - run: npm install --global markdownlint-cli2@0.23.1 + run: npm install --global markdownlint-cli2@0.23.2 - name: Run markdownlint-cli2 id: markdownlint run: | diff --git a/.github/workflows/markdown-linter.md b/.github/workflows/markdown-linter.md index b8e5f97f36..f90e2688e3 100644 --- a/.github/workflows/markdown-linter.md +++ b/.github/workflows/markdown-linter.md @@ -41,13 +41,13 @@ jobs: persist-credentials: false - name: Install markdownlint-cli2 # Pinned to the markdownlint-cli2 version bundled by - # DavidAnson/markdownlint-cli2-action@v24.1.0, which .github/workflows/markdownlint.yml + # DavidAnson/markdownlint-cli2-action@v24.2.0, which .github/workflows/markdownlint.yml # runs on every pull request, so this scheduled report and the pull request gate apply # exactly the same rules. Bump this together with that action. # Installed in its own step so that a registry outage or a bad version fails the job # here. npx exits 1 for those too, which the lint step below cannot tell apart from # "violations found", and it would report an npm error log as if it were lint results. - run: npm install --global markdownlint-cli2@0.23.1 + run: npm install --global markdownlint-cli2@0.23.2 - id: markdownlint name: Run markdownlint-cli2 # Configuration comes from .markdownlint-cli2.jsonc in the repo root, including its From 04fc28d702a03b41e9b8d5b8c8922c72cf274867 Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Tue, 25 Aug 2026 14:40:32 +0200 Subject: [PATCH 5/9] Report tooling failures instead of failing the lint job silently The agent job needs the markdownlint job, so failing that job on a tooling error skipped the agent and, with it, detection and safe_outputs. A registry outage or a broken config produced a red scheduled run and no issue at all, which is the unattended silence this workflow is meant to remove. Keep the job green and hand the agent a log whose first line is MARKDOWNLINT_RUN_FAILED, and teach the prompt to check for that marker before anything else and report a workflow failure rather than lint findings. The npm install keeps its own step and marks the log the same way instead of failing, so an install failure is reported rather than swallowed. Also stop Dependabot from bumping DavidAnson/markdownlint-cli2-action on its own. It pins the CLI version it bundles, and this workflow installs that same version by hand, so an unattended bump of one side would silently give the scheduled report and the pull request gate different rule sets. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/dependabot.yml | 6 +++ .github/workflows/markdown-linter.lock.yml | 40 ++++++++++++--- .github/workflows/markdown-linter.md | 58 +++++++++++++++++----- 3 files changed, 85 insertions(+), 19 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e290a3bedc..0010212fb9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -45,6 +45,12 @@ updates: # `awf: command not found` -> parse_error (see #10203). These are # updated via `gh aw upgrade` / the Agentic Maintenance workflow instead. - dependency-name: "github/gh-aw-actions/*" + # DavidAnson/markdownlint-cli2-action pins the CLI version it bundles, and + # `.github/workflows/markdown-linter.md` installs that same version by hand so the + # scheduled report and the pull request gate apply identical rules. Dependabot can + # only see the action, so letting it bump alone would silently give the two different + # rule sets. Move both pins together, by hand, when updating the action. + - dependency-name: "DavidAnson/markdownlint-cli2-action" commit-message: prefix: '[main] ' cooldown: diff --git a/.github/workflows/markdown-linter.lock.yml b/.github/workflows/markdown-linter.lock.yml index 4e58544283..a1574ca6b7 100644 --- a/.github/workflows/markdown-linter.lock.yml +++ b/.github/workflows/markdown-linter.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"647c8866e4a19f4956953431af4683d06f3c95808f352f81d92582250750117b","body_hash":"ce3fce41565b039f15e30e571a0c992db664a5e85eac45bfe4c5550f5829cd6f","compiler_version":"v0.86.2","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.79"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"1a5c034a58a8e6cfd2a55ee9a57940484a86b88aee32d671ec2a10c3d76e0c24","body_hash":"19792adcc3a8b6e14bdd2625e828e51b3821b8da2f5291e58a1bc9ce062eb69b","compiler_version":"v0.86.2","strict":true,"agent_id":"copilot","engine_versions":{"copilot":"1.0.79"}} # gh-aw-manifest: {"version":1,"secrets":["GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"6aab9e5b5c91c615506061f09bedd81a23babe3c","version":"v0.86.2"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44","digest":"sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44@sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44","digest":"sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44@sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44","digest":"sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44@sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.9","digest":"sha256:e5a1569aeaf41820fa7bdee3e94468cae448133cdbf00119ad24f5b74db1ab9f","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.9@sha256:e5a1569aeaf41820fa7bdee3e94468cae448133cdbf00119ad24f5b74db1ab9f"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196"},{"image":"ghcr.io/github/github-mcp-server:v1.9.0","digest":"sha256:881b53d6f75f69bdbc1b5b10fc2f1361717c19054143b3a8529fb5c32061a50e","pinned_image":"ghcr.io/github/github-mcp-server:v1.9.0@sha256:881b53d6f75f69bdbc1b5b10fc2f1361717c19054143b3a8529fb5c32061a50e"}]} # This file was automatically generated by gh-aw (v0.86.2). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -1565,21 +1565,47 @@ jobs: with: persist-credentials: false - name: Install markdownlint-cli2 - run: npm install --global markdownlint-cli2@0.23.2 + id: install + run: | + status=0 + npm install --global markdownlint-cli2@0.23.2 > install.log 2>&1 || status=$? + cat install.log + if [ "$status" -ne 0 ]; then + echo "::error::Installing markdownlint-cli2@0.23.2 failed (exit $status)." + echo "failed=true" >> "$GITHUB_OUTPUT" + # Hand the agent a marked log instead of failing the job. The agent job needs this + # one, so a red job here would skip the whole reporting chain and produce silence, + # which is the unattended failure this workflow exists to remove. + { + echo "MARKDOWNLINT_RUN_FAILED" + echo "npm install of markdownlint-cli2@0.23.2 failed with exit code $status." + echo "No Markdown files were linted." + echo + cat install.log + } > markdownlint.log + fi - name: Run markdownlint-cli2 id: markdownlint + if: steps.install.outputs.failed != 'true' run: | status=0 markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? cat markdownlint.log echo "markdownlint-cli2 exit code: $status (0 = clean, 1 = violations found)" - # Exit 1 means violations, which are what the agent reports on, so the job stays green. - # Anything above that is markdownlint-cli2 failing to run at all (2 = execution or - # configuration error). The log then holds a stack trace rather than lint results, so - # fail instead of letting the agent report "no issues" over a run that never linted. + # Exit 1 means violations, which are what the agent reports on. Anything above that is + # markdownlint-cli2 failing to run at all (2 = execution or configuration error), so the + # log holds a stack trace rather than lint results. Mark it so the agent reports a + # workflow failure instead of "no issues", and keep the job green either way: the agent + # job needs this one, so failing here would skip the reporting chain and say nothing. if [ "$status" -gt 1 ]; then echo "::error::markdownlint-cli2 could not complete (exit $status); see the log above." - exit "$status" + { + echo "MARKDOWNLINT_RUN_FAILED" + echo "markdownlint-cli2 exited $status without producing lint results." + echo + cat markdownlint.log + } > markdownlint.log.tmp + mv markdownlint.log.tmp markdownlint.log fi - name: Upload markdownlint log if: always() diff --git a/.github/workflows/markdown-linter.md b/.github/workflows/markdown-linter.md index f90e2688e3..5853497b56 100644 --- a/.github/workflows/markdown-linter.md +++ b/.github/workflows/markdown-linter.md @@ -39,16 +39,36 @@ jobs: uses: actions/checkout@v7.0.1 with: persist-credentials: false - - name: Install markdownlint-cli2 + - id: install + name: Install markdownlint-cli2 # Pinned to the markdownlint-cli2 version bundled by # DavidAnson/markdownlint-cli2-action@v24.2.0, which .github/workflows/markdownlint.yml # runs on every pull request, so this scheduled report and the pull request gate apply - # exactly the same rules. Bump this together with that action. - # Installed in its own step so that a registry outage or a bad version fails the job - # here. npx exits 1 for those too, which the lint step below cannot tell apart from + # exactly the same rules. Both pins are ignored by Dependabot (see .github/dependabot.yml) + # so they can only move together, by hand. + # Installed in its own step so that a registry outage or a bad version is caught here. + # npx exits 1 for those too, which the lint step below cannot tell apart from # "violations found", and it would report an npm error log as if it were lint results. - run: npm install --global markdownlint-cli2@0.23.2 + run: | + status=0 + npm install --global markdownlint-cli2@0.23.2 > install.log 2>&1 || status=$? + cat install.log + if [ "$status" -ne 0 ]; then + echo "::error::Installing markdownlint-cli2@0.23.2 failed (exit $status)." + echo "failed=true" >> "$GITHUB_OUTPUT" + # Hand the agent a marked log instead of failing the job. The agent job needs this + # one, so a red job here would skip the whole reporting chain and produce silence, + # which is the unattended failure this workflow exists to remove. + { + echo "MARKDOWNLINT_RUN_FAILED" + echo "npm install of markdownlint-cli2@0.23.2 failed with exit code $status." + echo "No Markdown files were linted." + echo + cat install.log + } > markdownlint.log + fi - id: markdownlint + if: steps.install.outputs.failed != 'true' name: Run markdownlint-cli2 # Configuration comes from .markdownlint-cli2.jsonc in the repo root, including its # "ignores" list. @@ -57,13 +77,20 @@ jobs: markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? cat markdownlint.log echo "markdownlint-cli2 exit code: $status (0 = clean, 1 = violations found)" - # Exit 1 means violations, which are what the agent reports on, so the job stays green. - # Anything above that is markdownlint-cli2 failing to run at all (2 = execution or - # configuration error). The log then holds a stack trace rather than lint results, so - # fail instead of letting the agent report "no issues" over a run that never linted. + # Exit 1 means violations, which are what the agent reports on. Anything above that is + # markdownlint-cli2 failing to run at all (2 = execution or configuration error), so the + # log holds a stack trace rather than lint results. Mark it so the agent reports a + # workflow failure instead of "no issues", and keep the job green either way: the agent + # job needs this one, so failing here would skip the reporting chain and say nothing. if [ "$status" -gt 1 ]; then echo "::error::markdownlint-cli2 could not complete (exit $status); see the log above." - exit "$status" + { + echo "MARKDOWNLINT_RUN_FAILED" + echo "markdownlint-cli2 exited $status without producing lint results." + echo + cat markdownlint.log + } > markdownlint.log.tmp + mv markdownlint.log.tmp markdownlint.log fi - if: always() name: Upload markdownlint log @@ -98,7 +125,14 @@ You are an expert documentation quality analyst. Your task is to analyze the mar ## Your Task 1. **Read the linter output** from `/tmp/gh-aw/markdownlint.log` using the bash tool -2. **Analyze the findings**: +2. **Check the first line for `MARKDOWNLINT_RUN_FAILED` before anything else.** If it is there, + markdownlint-cli2 never produced lint results — the rest of the file is an npm or runtime + error, not findings. Do not analyze it as lint output and do not report a clean run. Instead + create an issue titled + "Markdown Linter workflow failure - [Date] - markdownlint-cli2 did not run", + quoting the log and stating that Markdown went unlinted on this run so the result says + nothing about the repository's Markdown quality. Then stop; the steps below do not apply. +3. **Analyze the findings**: - Categorize errors by severity (critical, high, medium, low) - Identify patterns in the errors - Determine which errors are most important to fix first @@ -106,7 +140,7 @@ You are an expert documentation quality analyst. Your task is to analyze the mar `.markdownlint-cli2.jsonc` rules. The same rules gate every pull request through `.github/workflows/markdownlint.yml`, so anything reported here also blocks new pull requests. Rules that file disables (for example MD013 line length) are not violations. -3. **Create a detailed issue** with the following structure: +4. **Create a detailed issue** with the following structure: ### Issue Title Use format: "Markdown Quality Report - [Date] - [X] issues found" From 919fdc4080518730f588b580e51db94b113bc9aa Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Tue, 25 Aug 2026 15:58:24 +0200 Subject: [PATCH 6/9] Bound the lint job with a timeout Without timeout-minutes the job inherits GitHub's six-hour default, so a stalled npm install or linter holds the workflow's concurrency group for hours and then fails the job. The agent job needs this one, so that failure also skips the reporting chain and the scheduled run says nothing -- the silence this workflow exists to remove. The pull request gate finishes in seconds under a 5 minute cap; 10 leaves headroom. Also correct the workflow catalog: this workflow has only schedule and workflow_dispatch triggers, so the trigger column is "Schedule + manual". Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/README.md | 2 +- .github/workflows/markdown-linter.lock.yml | 3 ++- .github/workflows/markdown-linter.md | 5 +++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/README.md b/.github/workflows/README.md index fec7611c88..874714420c 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -312,7 +312,7 @@ so turning the check off would remove a security control that is working. | [`unskip-closed-tests.md`](./unskip-closed-tests.md) | Weekly + manual | Finds tests skipped via `[Ignore("…#issue")]` whose tracking issue is now closed, verifies they pass, and opens a PR re-enabling them. | | [`duplicate-code-detector.md`](./duplicate-code-detector.md) | Schedule + manual | Identifies duplicate code patterns and suggests refactoring opportunities. | | [`malicious-code-scan.md`](./malicious-code-scan.md) | Schedule + manual | Reviews code changes from the last 3 days for suspicious patterns indicating malicious or agentic threats. | -| [`markdown-linter.md`](./markdown-linter.md) | Schedule + manual + issues | Runs Markdown quality checks using markdownlint-cli2 and opens issues for violations. | +| [`markdown-linter.md`](./markdown-linter.md) | Schedule + manual | Runs Markdown quality checks using markdownlint-cli2 and opens issues for violations. | | [`link-checker.md`](./link-checker.md) | Daily | Daily automated link checker that finds and fixes broken links in documentation files. | | [`glossary-maintainer.md`](./glossary-maintainer.md) | Schedule + manual | Maintains and updates the documentation glossary based on codebase changes. | diff --git a/.github/workflows/markdown-linter.lock.yml b/.github/workflows/markdown-linter.lock.yml index fc5cc0e598..b811d6907c 100644 --- a/.github/workflows/markdown-linter.lock.yml +++ b/.github/workflows/markdown-linter.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"c06c9134988f649ff55b8c0eb80bd3cd24016576002adf94b8095b053a152b25","body_hash":"19792adcc3a8b6e14bdd2625e828e51b3821b8da2f5291e58a1bc9ce062eb69b","compiler_version":"v0.86.2","strict":true,"agent_id":"copilot","detection_agent_id":"copilot","detection_agent_model":"gpt-5-mini","engine_versions":{"copilot":"1.0.79"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"7885c54d41976b17f5e4f2da72bc04a65de60d4fc0f824849c05dff3d8ad8534","body_hash":"19792adcc3a8b6e14bdd2625e828e51b3821b8da2f5291e58a1bc9ce062eb69b","compiler_version":"v0.86.2","strict":true,"agent_id":"copilot","detection_agent_id":"copilot","detection_agent_model":"gpt-5-mini","engine_versions":{"copilot":"1.0.79"}} # gh-aw-manifest: {"version":1,"secrets":["GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"6aab9e5b5c91c615506061f09bedd81a23babe3c","version":"v0.86.2"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44","digest":"sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44@sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44","digest":"sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44@sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44","digest":"sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44@sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.9","digest":"sha256:e5a1569aeaf41820fa7bdee3e94468cae448133cdbf00119ad24f5b74db1ab9f","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.9@sha256:e5a1569aeaf41820fa7bdee3e94468cae448133cdbf00119ad24f5b74db1ab9f"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196"},{"image":"ghcr.io/github/github-mcp-server:v1.9.0","digest":"sha256:881b53d6f75f69bdbc1b5b10fc2f1361717c19054143b3a8529fb5c32061a50e","pinned_image":"ghcr.io/github/github-mcp-server:v1.9.0@sha256:881b53d6f75f69bdbc1b5b10fc2f1361717c19054143b3a8529fb5c32061a50e"}]} # This file was automatically generated by gh-aw (v0.86.2). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -1550,6 +1550,7 @@ jobs: runs-on: ubuntu-latest permissions: contents: read + timeout-minutes: 10 steps: - name: Configure GH_HOST for enterprise compatibility id: ghes-host-config diff --git a/.github/workflows/markdown-linter.md b/.github/workflows/markdown-linter.md index 0b4c50bb7b..8379b77f23 100644 --- a/.github/workflows/markdown-linter.md +++ b/.github/workflows/markdown-linter.md @@ -40,6 +40,11 @@ jobs: permissions: contents: read runs-on: ubuntu-latest + # A stalled npm install or linter would otherwise inherit GitHub's six-hour default and + # hold the workflow's concurrency group. A timeout fails this job, and the agent job needs + # it, so that would also skip the reporting chain -- the silence this workflow exists to + # remove. The pull request gate finishes in seconds with a 5 minute cap; 10 leaves headroom. + timeout-minutes: 10 steps: - name: Checkout repository uses: actions/checkout@v7.0.1 From 550884250bb96f3dcb47dba02712add45b45003e Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Tue, 25 Aug 2026 16:10:41 +0200 Subject: [PATCH 7/9] Bound the install and lint commands so a stall is reported, not silent The job-level timeout added in the previous commit caps the runaway, but GitHub kills the job when it fires, so the script never runs its marker branch: no log is written, no artifact is uploaded, and the agent job is skipped. A stall was still a red run with no issue. Wrap both commands in `timeout 5m`, below the job's 10 minute cap. timeout exits 124, which is greater than 1 and so already routes into the existing failure branch; the messages name the timeout specifically. Verified against a real stall: exit 124 marks the log and the step still exits 0. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/markdown-linter.lock.yml | 36 +++++++++++++------ .github/workflows/markdown-linter.md | 42 ++++++++++++++++------ 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/.github/workflows/markdown-linter.lock.yml b/.github/workflows/markdown-linter.lock.yml index b811d6907c..320f0bf71a 100644 --- a/.github/workflows/markdown-linter.lock.yml +++ b/.github/workflows/markdown-linter.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"7885c54d41976b17f5e4f2da72bc04a65de60d4fc0f824849c05dff3d8ad8534","body_hash":"19792adcc3a8b6e14bdd2625e828e51b3821b8da2f5291e58a1bc9ce062eb69b","compiler_version":"v0.86.2","strict":true,"agent_id":"copilot","detection_agent_id":"copilot","detection_agent_model":"gpt-5-mini","engine_versions":{"copilot":"1.0.79"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"61d430db43496934c542f1b5369b796ddfaed6bd2e3a749fa1c0a987db48e335","body_hash":"19792adcc3a8b6e14bdd2625e828e51b3821b8da2f5291e58a1bc9ce062eb69b","compiler_version":"v0.86.2","strict":true,"agent_id":"copilot","detection_agent_id":"copilot","detection_agent_model":"gpt-5-mini","engine_versions":{"copilot":"1.0.79"}} # gh-aw-manifest: {"version":1,"secrets":["GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"6aab9e5b5c91c615506061f09bedd81a23babe3c","version":"v0.86.2"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44","digest":"sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44@sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44","digest":"sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44@sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44","digest":"sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44@sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.9","digest":"sha256:e5a1569aeaf41820fa7bdee3e94468cae448133cdbf00119ad24f5b74db1ab9f","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.9@sha256:e5a1569aeaf41820fa7bdee3e94468cae448133cdbf00119ad24f5b74db1ab9f"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196"},{"image":"ghcr.io/github/github-mcp-server:v1.9.0","digest":"sha256:881b53d6f75f69bdbc1b5b10fc2f1361717c19054143b3a8529fb5c32061a50e","pinned_image":"ghcr.io/github/github-mcp-server:v1.9.0@sha256:881b53d6f75f69bdbc1b5b10fc2f1361717c19054143b3a8529fb5c32061a50e"}]} # This file was automatically generated by gh-aw (v0.86.2). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -1569,10 +1569,14 @@ jobs: id: install run: | status=0 - npm install --global markdownlint-cli2@0.23.2 > install.log 2>&1 || status=$? + timeout 5m npm install --global markdownlint-cli2@0.23.2 > install.log 2>&1 || status=$? cat install.log if [ "$status" -ne 0 ]; then - echo "::error::Installing markdownlint-cli2@0.23.2 failed (exit $status)." + if [ "$status" -eq 124 ]; then + echo "::error::Installing markdownlint-cli2@0.23.2 timed out after 5 minutes." + else + echo "::error::Installing markdownlint-cli2@0.23.2 failed (exit $status)." + fi echo "failed=true" >> "$GITHUB_OUTPUT" # Hand the agent a marked log instead of failing the job. The agent job needs this # one, so a red job here would skip the whole reporting chain and produce silence, @@ -1580,6 +1584,9 @@ jobs: { echo "MARKDOWNLINT_RUN_FAILED" echo "npm install of markdownlint-cli2@0.23.2 failed with exit code $status." + if [ "$status" -eq 124 ]; then + echo "The install timed out after 5 minutes." + fi echo "No Markdown files were linted." echo cat install.log @@ -1590,19 +1597,28 @@ jobs: if: steps.install.outputs.failed != 'true' run: | status=0 - markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? + timeout 5m markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? cat markdownlint.log echo "markdownlint-cli2 exit code: $status (0 = clean, 1 = violations found)" # Exit 1 means violations, which are what the agent reports on. Anything above that is - # markdownlint-cli2 failing to run at all (2 = execution or configuration error), so the - # log holds a stack trace rather than lint results. Mark it so the agent reports a - # workflow failure instead of "no issues", and keep the job green either way: the agent - # job needs this one, so failing here would skip the reporting chain and say nothing. + # markdownlint-cli2 failing to run at all (2 = execution or configuration error, 124 = + # timed out), so the log holds a stack trace or nothing rather than lint results. Mark + # it so the agent reports a workflow failure instead of "no issues", and keep the job + # green either way: the agent job needs this one, so failing here would skip the + # reporting chain and say nothing. if [ "$status" -gt 1 ]; then - echo "::error::markdownlint-cli2 could not complete (exit $status); see the log above." + if [ "$status" -eq 124 ]; then + echo "::error::markdownlint-cli2 timed out after 5 minutes." + else + echo "::error::markdownlint-cli2 could not complete (exit $status); see the log above." + fi { echo "MARKDOWNLINT_RUN_FAILED" - echo "markdownlint-cli2 exited $status without producing lint results." + if [ "$status" -eq 124 ]; then + echo "markdownlint-cli2 timed out after 5 minutes without producing lint results." + else + echo "markdownlint-cli2 exited $status without producing lint results." + fi echo cat markdownlint.log } > markdownlint.log.tmp diff --git a/.github/workflows/markdown-linter.md b/.github/workflows/markdown-linter.md index 8379b77f23..f0e810533e 100644 --- a/.github/workflows/markdown-linter.md +++ b/.github/workflows/markdown-linter.md @@ -60,12 +60,20 @@ jobs: # Installed in its own step so that a registry outage or a bad version is caught here. # npx exits 1 for those too, which the lint step below cannot tell apart from # "violations found", and it would report an npm error log as if it were lint results. + # The command-level timeout sits below the job's 10 minute cap on purpose: a job-level + # timeout kills this script outright, so nothing would be marked or uploaded and the + # agent would be skipped. `timeout` exits 124 instead, which the check below treats + # like any other failure, so a stalled install still gets reported. run: | status=0 - npm install --global markdownlint-cli2@0.23.2 > install.log 2>&1 || status=$? + timeout 5m npm install --global markdownlint-cli2@0.23.2 > install.log 2>&1 || status=$? cat install.log if [ "$status" -ne 0 ]; then - echo "::error::Installing markdownlint-cli2@0.23.2 failed (exit $status)." + if [ "$status" -eq 124 ]; then + echo "::error::Installing markdownlint-cli2@0.23.2 timed out after 5 minutes." + else + echo "::error::Installing markdownlint-cli2@0.23.2 failed (exit $status)." + fi echo "failed=true" >> "$GITHUB_OUTPUT" # Hand the agent a marked log instead of failing the job. The agent job needs this # one, so a red job here would skip the whole reporting chain and produce silence, @@ -73,6 +81,9 @@ jobs: { echo "MARKDOWNLINT_RUN_FAILED" echo "npm install of markdownlint-cli2@0.23.2 failed with exit code $status." + if [ "$status" -eq 124 ]; then + echo "The install timed out after 5 minutes." + fi echo "No Markdown files were linted." echo cat install.log @@ -82,22 +93,33 @@ jobs: if: steps.install.outputs.failed != 'true' name: Run markdownlint-cli2 # Configuration comes from .markdownlint-cli2.jsonc in the repo root, including its - # "ignores" list. + # "ignores" list. The command-level timeout sits below the job's 10 minute cap for the + # same reason as the install step: a job-level timeout would kill this script before it + # could mark the log, leaving the agent skipped and the run silent. run: | status=0 - markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? + timeout 5m markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? cat markdownlint.log echo "markdownlint-cli2 exit code: $status (0 = clean, 1 = violations found)" # Exit 1 means violations, which are what the agent reports on. Anything above that is - # markdownlint-cli2 failing to run at all (2 = execution or configuration error), so the - # log holds a stack trace rather than lint results. Mark it so the agent reports a - # workflow failure instead of "no issues", and keep the job green either way: the agent - # job needs this one, so failing here would skip the reporting chain and say nothing. + # markdownlint-cli2 failing to run at all (2 = execution or configuration error, 124 = + # timed out), so the log holds a stack trace or nothing rather than lint results. Mark + # it so the agent reports a workflow failure instead of "no issues", and keep the job + # green either way: the agent job needs this one, so failing here would skip the + # reporting chain and say nothing. if [ "$status" -gt 1 ]; then - echo "::error::markdownlint-cli2 could not complete (exit $status); see the log above." + if [ "$status" -eq 124 ]; then + echo "::error::markdownlint-cli2 timed out after 5 minutes." + else + echo "::error::markdownlint-cli2 could not complete (exit $status); see the log above." + fi { echo "MARKDOWNLINT_RUN_FAILED" - echo "markdownlint-cli2 exited $status without producing lint results." + if [ "$status" -eq 124 ]; then + echo "markdownlint-cli2 timed out after 5 minutes without producing lint results." + else + echo "markdownlint-cli2 exited $status without producing lint results." + fi echo cat markdownlint.log } > markdownlint.log.tmp From 92afb32141549655682d7db57597912467a3be3b Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Tue, 25 Aug 2026 16:24:38 +0200 Subject: [PATCH 8/9] Make the command timeouts fit inside the job timeout The two commands run in sequence, so a 5 minute cap on each could consume the whole 10 minute job cap before the second one wrote and uploaded its failure marker. GitHub would then kill the job and the stall would go unreported again, which is what the command caps were added to prevent. Cut both command caps to 3 minutes: 3 + 3 leaves 4 minutes for checkout, the marker write and the artifact upload. The job takes about 15 seconds in practice, so 3 minutes is still roughly 45x the observed install and 18x the lint. The comments now state the arithmetic so the three numbers stay consistent. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/markdown-linter.lock.yml | 14 +++++------ .github/workflows/markdown-linter.md | 27 +++++++++++++--------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/.github/workflows/markdown-linter.lock.yml b/.github/workflows/markdown-linter.lock.yml index 320f0bf71a..bcfe09f5ad 100644 --- a/.github/workflows/markdown-linter.lock.yml +++ b/.github/workflows/markdown-linter.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"61d430db43496934c542f1b5369b796ddfaed6bd2e3a749fa1c0a987db48e335","body_hash":"19792adcc3a8b6e14bdd2625e828e51b3821b8da2f5291e58a1bc9ce062eb69b","compiler_version":"v0.86.2","strict":true,"agent_id":"copilot","detection_agent_id":"copilot","detection_agent_model":"gpt-5-mini","engine_versions":{"copilot":"1.0.79"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"dc87f28cddbd29375cbcb49ed66f22a815eb010f7d05645b2e578d4c9200bf33","body_hash":"19792adcc3a8b6e14bdd2625e828e51b3821b8da2f5291e58a1bc9ce062eb69b","compiler_version":"v0.86.2","strict":true,"agent_id":"copilot","detection_agent_id":"copilot","detection_agent_model":"gpt-5-mini","engine_versions":{"copilot":"1.0.79"}} # gh-aw-manifest: {"version":1,"secrets":["GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"6aab9e5b5c91c615506061f09bedd81a23babe3c","version":"v0.86.2"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44","digest":"sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44@sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44","digest":"sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44@sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44","digest":"sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44@sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.9","digest":"sha256:e5a1569aeaf41820fa7bdee3e94468cae448133cdbf00119ad24f5b74db1ab9f","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.9@sha256:e5a1569aeaf41820fa7bdee3e94468cae448133cdbf00119ad24f5b74db1ab9f"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196"},{"image":"ghcr.io/github/github-mcp-server:v1.9.0","digest":"sha256:881b53d6f75f69bdbc1b5b10fc2f1361717c19054143b3a8529fb5c32061a50e","pinned_image":"ghcr.io/github/github-mcp-server:v1.9.0@sha256:881b53d6f75f69bdbc1b5b10fc2f1361717c19054143b3a8529fb5c32061a50e"}]} # This file was automatically generated by gh-aw (v0.86.2). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -1569,11 +1569,11 @@ jobs: id: install run: | status=0 - timeout 5m npm install --global markdownlint-cli2@0.23.2 > install.log 2>&1 || status=$? + timeout 3m npm install --global markdownlint-cli2@0.23.2 > install.log 2>&1 || status=$? cat install.log if [ "$status" -ne 0 ]; then if [ "$status" -eq 124 ]; then - echo "::error::Installing markdownlint-cli2@0.23.2 timed out after 5 minutes." + echo "::error::Installing markdownlint-cli2@0.23.2 timed out after 3 minutes." else echo "::error::Installing markdownlint-cli2@0.23.2 failed (exit $status)." fi @@ -1585,7 +1585,7 @@ jobs: echo "MARKDOWNLINT_RUN_FAILED" echo "npm install of markdownlint-cli2@0.23.2 failed with exit code $status." if [ "$status" -eq 124 ]; then - echo "The install timed out after 5 minutes." + echo "The install timed out after 3 minutes." fi echo "No Markdown files were linted." echo @@ -1597,7 +1597,7 @@ jobs: if: steps.install.outputs.failed != 'true' run: | status=0 - timeout 5m markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? + timeout 3m markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? cat markdownlint.log echo "markdownlint-cli2 exit code: $status (0 = clean, 1 = violations found)" # Exit 1 means violations, which are what the agent reports on. Anything above that is @@ -1608,14 +1608,14 @@ jobs: # reporting chain and say nothing. if [ "$status" -gt 1 ]; then if [ "$status" -eq 124 ]; then - echo "::error::markdownlint-cli2 timed out after 5 minutes." + echo "::error::markdownlint-cli2 timed out after 3 minutes." else echo "::error::markdownlint-cli2 could not complete (exit $status); see the log above." fi { echo "MARKDOWNLINT_RUN_FAILED" if [ "$status" -eq 124 ]; then - echo "markdownlint-cli2 timed out after 5 minutes without producing lint results." + echo "markdownlint-cli2 timed out after 3 minutes without producing lint results." else echo "markdownlint-cli2 exited $status without producing lint results." fi diff --git a/.github/workflows/markdown-linter.md b/.github/workflows/markdown-linter.md index f0e810533e..e2c9c8c32d 100644 --- a/.github/workflows/markdown-linter.md +++ b/.github/workflows/markdown-linter.md @@ -41,9 +41,12 @@ jobs: contents: read runs-on: ubuntu-latest # A stalled npm install or linter would otherwise inherit GitHub's six-hour default and - # hold the workflow's concurrency group. A timeout fails this job, and the agent job needs - # it, so that would also skip the reporting chain -- the silence this workflow exists to - # remove. The pull request gate finishes in seconds with a 5 minute cap; 10 leaves headroom. + # hold the workflow's concurrency group. A job timeout kills the step outright, so the + # steps below cap their own commands at 3 minutes each and report the stall instead. This + # job cap is the backstop, and it has to stay above both command caps plus the checkout + # and artifact upload: 3 + 3 = 6 minutes of commands leaves 4 minutes of headroom, so the + # second command's failure marker still gets written and uploaded. Keep that arithmetic + # true if you change any of the three numbers. The job takes about 15 seconds in practice. timeout-minutes: 10 steps: - name: Checkout repository @@ -63,14 +66,15 @@ jobs: # The command-level timeout sits below the job's 10 minute cap on purpose: a job-level # timeout kills this script outright, so nothing would be marked or uploaded and the # agent would be skipped. `timeout` exits 124 instead, which the check below treats - # like any other failure, so a stalled install still gets reported. + # like any other failure, so a stalled install still gets reported. 3 minutes is about + # 45x the observed install time and leaves room for the lint step's own cap. run: | status=0 - timeout 5m npm install --global markdownlint-cli2@0.23.2 > install.log 2>&1 || status=$? + timeout 3m npm install --global markdownlint-cli2@0.23.2 > install.log 2>&1 || status=$? cat install.log if [ "$status" -ne 0 ]; then if [ "$status" -eq 124 ]; then - echo "::error::Installing markdownlint-cli2@0.23.2 timed out after 5 minutes." + echo "::error::Installing markdownlint-cli2@0.23.2 timed out after 3 minutes." else echo "::error::Installing markdownlint-cli2@0.23.2 failed (exit $status)." fi @@ -82,7 +86,7 @@ jobs: echo "MARKDOWNLINT_RUN_FAILED" echo "npm install of markdownlint-cli2@0.23.2 failed with exit code $status." if [ "$status" -eq 124 ]; then - echo "The install timed out after 5 minutes." + echo "The install timed out after 3 minutes." fi echo "No Markdown files were linted." echo @@ -95,10 +99,11 @@ jobs: # Configuration comes from .markdownlint-cli2.jsonc in the repo root, including its # "ignores" list. The command-level timeout sits below the job's 10 minute cap for the # same reason as the install step: a job-level timeout would kill this script before it - # could mark the log, leaving the agent skipped and the run silent. + # could mark the log, leaving the agent skipped and the run silent. 3 minutes is about + # 18x the observed lint time, and 3 + 3 stays clear of the job cap. run: | status=0 - timeout 5m markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? + timeout 3m markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? cat markdownlint.log echo "markdownlint-cli2 exit code: $status (0 = clean, 1 = violations found)" # Exit 1 means violations, which are what the agent reports on. Anything above that is @@ -109,14 +114,14 @@ jobs: # reporting chain and say nothing. if [ "$status" -gt 1 ]; then if [ "$status" -eq 124 ]; then - echo "::error::markdownlint-cli2 timed out after 5 minutes." + echo "::error::markdownlint-cli2 timed out after 3 minutes." else echo "::error::markdownlint-cli2 could not complete (exit $status); see the log above." fi { echo "MARKDOWNLINT_RUN_FAILED" if [ "$status" -eq 124 ]; then - echo "markdownlint-cli2 timed out after 5 minutes without producing lint results." + echo "markdownlint-cli2 timed out after 3 minutes without producing lint results." else echo "markdownlint-cli2 exited $status without producing lint results." fi From 5422779d757ab1a7e0fcd808f840909159db4cf5 Mon Sep 17 00:00:00 2001 From: Jakub Jares Date: Tue, 25 Aug 2026 16:38:19 +0200 Subject: [PATCH 9/9] Force SIGKILL when a stalled command ignores SIGTERM `timeout` alone sends only SIGTERM, so a command that ignores it keeps running and the job-level timeout kills the job before the failure marker is written or uploaded. The command caps could not bound a genuinely hung process. Add --kill-after=30s to both commands. The grace period forces SIGKILL, which surfaces as 137 rather than 124, so both codes now count as a timeout. Worst case is 3m plus 30s per command, 7 minutes for the pair, still inside the 10 minute job cap. Verified against a process that traps and ignores SIGTERM: without the grace period it outlived its cap entirely; with it the command is killed, reports 137 and the log is marked. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/markdown-linter.lock.yml | 22 ++++++------- .github/workflows/markdown-linter.md | 36 ++++++++++++---------- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/.github/workflows/markdown-linter.lock.yml b/.github/workflows/markdown-linter.lock.yml index bcfe09f5ad..6e4b04c108 100644 --- a/.github/workflows/markdown-linter.lock.yml +++ b/.github/workflows/markdown-linter.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"dc87f28cddbd29375cbcb49ed66f22a815eb010f7d05645b2e578d4c9200bf33","body_hash":"19792adcc3a8b6e14bdd2625e828e51b3821b8da2f5291e58a1bc9ce062eb69b","compiler_version":"v0.86.2","strict":true,"agent_id":"copilot","detection_agent_id":"copilot","detection_agent_model":"gpt-5-mini","engine_versions":{"copilot":"1.0.79"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"c578e39861dab3748c3a2b9c06a17f57702cf7f311aa33b5ff8ca47203595bc1","body_hash":"19792adcc3a8b6e14bdd2625e828e51b3821b8da2f5291e58a1bc9ce062eb69b","compiler_version":"v0.86.2","strict":true,"agent_id":"copilot","detection_agent_id":"copilot","detection_agent_model":"gpt-5-mini","engine_versions":{"copilot":"1.0.79"}} # gh-aw-manifest: {"version":1,"secrets":["GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"6aab9e5b5c91c615506061f09bedd81a23babe3c","version":"v0.86.2"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44","digest":"sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.44@sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44","digest":"sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.44@sha256:b50fbadba138f6e9aba94aca09711335c489bb3b15861220cb66f6092e042dc7"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44","digest":"sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.44@sha256:83e48bbe12c634be8c228a576832fe45f66c529ac3659db92bddbcf2eeb6d627"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.9","digest":"sha256:e5a1569aeaf41820fa7bdee3e94468cae448133cdbf00119ad24f5b74db1ab9f","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.9@sha256:e5a1569aeaf41820fa7bdee3e94468cae448133cdbf00119ad24f5b74db1ab9f"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196","pinned_image":"ghcr.io/github/gh-aw-node@sha256:0d9f1fb5fd6610c0ac1f5194a38e45a8a1e81f8a390d5142d8e4e6f26a4b3196"},{"image":"ghcr.io/github/github-mcp-server:v1.9.0","digest":"sha256:881b53d6f75f69bdbc1b5b10fc2f1361717c19054143b3a8529fb5c32061a50e","pinned_image":"ghcr.io/github/github-mcp-server:v1.9.0@sha256:881b53d6f75f69bdbc1b5b10fc2f1361717c19054143b3a8529fb5c32061a50e"}]} # This file was automatically generated by gh-aw (v0.86.2). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -1569,10 +1569,10 @@ jobs: id: install run: | status=0 - timeout 3m npm install --global markdownlint-cli2@0.23.2 > install.log 2>&1 || status=$? + timeout --kill-after=30s 3m npm install --global markdownlint-cli2@0.23.2 > install.log 2>&1 || status=$? cat install.log if [ "$status" -ne 0 ]; then - if [ "$status" -eq 124 ]; then + if [ "$status" -eq 124 ] || [ "$status" -eq 137 ]; then echo "::error::Installing markdownlint-cli2@0.23.2 timed out after 3 minutes." else echo "::error::Installing markdownlint-cli2@0.23.2 failed (exit $status)." @@ -1584,7 +1584,7 @@ jobs: { echo "MARKDOWNLINT_RUN_FAILED" echo "npm install of markdownlint-cli2@0.23.2 failed with exit code $status." - if [ "$status" -eq 124 ]; then + if [ "$status" -eq 124 ] || [ "$status" -eq 137 ]; then echo "The install timed out after 3 minutes." fi echo "No Markdown files were linted." @@ -1597,24 +1597,24 @@ jobs: if: steps.install.outputs.failed != 'true' run: | status=0 - timeout 3m markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? + timeout --kill-after=30s 3m markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? cat markdownlint.log echo "markdownlint-cli2 exit code: $status (0 = clean, 1 = violations found)" # Exit 1 means violations, which are what the agent reports on. Anything above that is - # markdownlint-cli2 failing to run at all (2 = execution or configuration error, 124 = - # timed out), so the log holds a stack trace or nothing rather than lint results. Mark - # it so the agent reports a workflow failure instead of "no issues", and keep the job - # green either way: the agent job needs this one, so failing here would skip the + # markdownlint-cli2 failing to run at all (2 = execution or configuration error, 124 or + # 137 = timed out), so the log holds a stack trace or nothing rather than lint results. + # Mark it so the agent reports a workflow failure instead of "no issues", and keep the + # job green either way: the agent job needs this one, so failing here would skip the # reporting chain and say nothing. if [ "$status" -gt 1 ]; then - if [ "$status" -eq 124 ]; then + if [ "$status" -eq 124 ] || [ "$status" -eq 137 ]; then echo "::error::markdownlint-cli2 timed out after 3 minutes." else echo "::error::markdownlint-cli2 could not complete (exit $status); see the log above." fi { echo "MARKDOWNLINT_RUN_FAILED" - if [ "$status" -eq 124 ]; then + if [ "$status" -eq 124 ] || [ "$status" -eq 137 ]; then echo "markdownlint-cli2 timed out after 3 minutes without producing lint results." else echo "markdownlint-cli2 exited $status without producing lint results." diff --git a/.github/workflows/markdown-linter.md b/.github/workflows/markdown-linter.md index e2c9c8c32d..c88b87fdae 100644 --- a/.github/workflows/markdown-linter.md +++ b/.github/workflows/markdown-linter.md @@ -42,11 +42,11 @@ jobs: runs-on: ubuntu-latest # A stalled npm install or linter would otherwise inherit GitHub's six-hour default and # hold the workflow's concurrency group. A job timeout kills the step outright, so the - # steps below cap their own commands at 3 minutes each and report the stall instead. This - # job cap is the backstop, and it has to stay above both command caps plus the checkout - # and artifact upload: 3 + 3 = 6 minutes of commands leaves 4 minutes of headroom, so the - # second command's failure marker still gets written and uploaded. Keep that arithmetic - # true if you change any of the three numbers. The job takes about 15 seconds in practice. + # steps below cap their own commands and report the stall instead. This job cap is the + # backstop, and it has to stay above both command caps plus the checkout and artifact + # upload: 3m + 30s of kill grace, twice, is 7 minutes and leaves 3 minutes of headroom, so + # the second command's failure marker still gets written and uploaded. Keep that + # arithmetic true if you change any of the numbers. The job takes about 15 seconds. timeout-minutes: 10 steps: - name: Checkout repository @@ -68,12 +68,15 @@ jobs: # agent would be skipped. `timeout` exits 124 instead, which the check below treats # like any other failure, so a stalled install still gets reported. 3 minutes is about # 45x the observed install time and leaves room for the lint step's own cap. + # --kill-after matters: `timeout` alone only sends SIGTERM, so a process that ignores it + # keeps running and the job cap kills the job before anything is marked. The grace period + # forces SIGKILL, which surfaces as 137 rather than 124. run: | status=0 - timeout 3m npm install --global markdownlint-cli2@0.23.2 > install.log 2>&1 || status=$? + timeout --kill-after=30s 3m npm install --global markdownlint-cli2@0.23.2 > install.log 2>&1 || status=$? cat install.log if [ "$status" -ne 0 ]; then - if [ "$status" -eq 124 ]; then + if [ "$status" -eq 124 ] || [ "$status" -eq 137 ]; then echo "::error::Installing markdownlint-cli2@0.23.2 timed out after 3 minutes." else echo "::error::Installing markdownlint-cli2@0.23.2 failed (exit $status)." @@ -85,7 +88,7 @@ jobs: { echo "MARKDOWNLINT_RUN_FAILED" echo "npm install of markdownlint-cli2@0.23.2 failed with exit code $status." - if [ "$status" -eq 124 ]; then + if [ "$status" -eq 124 ] || [ "$status" -eq 137 ]; then echo "The install timed out after 3 minutes." fi echo "No Markdown files were linted." @@ -100,27 +103,28 @@ jobs: # "ignores" list. The command-level timeout sits below the job's 10 minute cap for the # same reason as the install step: a job-level timeout would kill this script before it # could mark the log, leaving the agent skipped and the run silent. 3 minutes is about - # 18x the observed lint time, and 3 + 3 stays clear of the job cap. + # 18x the observed lint time, and the caps stay clear of the job cap. --kill-after forces + # SIGKILL if the linter ignores SIGTERM, which surfaces as 137 rather than 124. run: | status=0 - timeout 3m markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? + timeout --kill-after=30s 3m markdownlint-cli2 "**/*.md" > markdownlint.log 2>&1 || status=$? cat markdownlint.log echo "markdownlint-cli2 exit code: $status (0 = clean, 1 = violations found)" # Exit 1 means violations, which are what the agent reports on. Anything above that is - # markdownlint-cli2 failing to run at all (2 = execution or configuration error, 124 = - # timed out), so the log holds a stack trace or nothing rather than lint results. Mark - # it so the agent reports a workflow failure instead of "no issues", and keep the job - # green either way: the agent job needs this one, so failing here would skip the + # markdownlint-cli2 failing to run at all (2 = execution or configuration error, 124 or + # 137 = timed out), so the log holds a stack trace or nothing rather than lint results. + # Mark it so the agent reports a workflow failure instead of "no issues", and keep the + # job green either way: the agent job needs this one, so failing here would skip the # reporting chain and say nothing. if [ "$status" -gt 1 ]; then - if [ "$status" -eq 124 ]; then + if [ "$status" -eq 124 ] || [ "$status" -eq 137 ]; then echo "::error::markdownlint-cli2 timed out after 3 minutes." else echo "::error::markdownlint-cli2 could not complete (exit $status); see the log above." fi { echo "MARKDOWNLINT_RUN_FAILED" - if [ "$status" -eq 124 ]; then + if [ "$status" -eq 124 ] || [ "$status" -eq 137 ]; then echo "markdownlint-cli2 timed out after 3 minutes without producing lint results." else echo "markdownlint-cli2 exited $status without producing lint results."