diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 83dc6a5a18..23e99906ef 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -47,6 +47,12 @@ updates: # updated via `gh aw upgrade` / the Agentic Maintenance workflow instead. - dependency-name: "github/gh-aw-actions/*" - dependency-name: "github/gh-aw/actions/setup" + # 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/README.md b/.github/workflows/README.md index 8bdaccfab5..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 Super Linter 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 2e2f806d01..6e4b04c108 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":"f69dce0b967e3c4ebaffe5dbce4ca3301a97af3210ffd5ca775f28fe5d3fda42","body_hash":"ed3f1406f293f05f3f2ab01d7bff4688be36f7d1e7968ee6d049bee6c903d91d","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"},{"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.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"}]} +# 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 # # ___ _ _ @@ -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: @@ -46,7 +44,6 @@ # - actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # - github/gh-aw-actions/setup@6aab9e5b5c91c615506061f09bedd81a23babe3c # v0.86.2 -# - super-linter/super-linter@4ce20838b8ab83717e78138c5b3a1407148e0918 # v8.7.0 # # Container images used: # - ghcr.io/github/gh-aw-firewall/agent:0.27.44@sha256:0d727725c737b58c7bdf51f640cffb928385ec46517e0917c7f1a02f1bada8b4 @@ -112,7 +109,6 @@ jobs: GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/markdown-linter.lock.yml@${{ github.ref }} GH_AW_INFO_VERSION: "1.0.79" 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_AWMG_VERSION: "" GH_AW_INFO_FIREWALL_TYPE: "squid" GH_AW_INFO_AGENT_RUNTIME: "" - 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: @@ -360,7 +354,7 @@ jobs: agent: needs: - activation - - super_linter + - markdownlint if: needs.activation.outputs.daily_ai_credits_exceeded != 'true' runs-on: ubuntu-latest permissions: @@ -419,7 +413,6 @@ jobs: GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/markdown-linter.lock.yml@${{ github.ref }} GH_AW_INFO_VERSION: "1.0.79" 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 @@ -460,10 +453,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 @@ -1027,8 +1020,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' || @@ -1063,7 +1056,6 @@ jobs: GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/markdown-linter.lock.yml@${{ github.ref }} GH_AW_INFO_VERSION: "1.0.79" 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 @@ -1155,8 +1147,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" @@ -1177,8 +1168,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 }} @@ -1196,8 +1186,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: | @@ -1212,8 +1201,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: | @@ -1228,8 +1216,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" @@ -1280,8 +1267,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: @@ -1322,7 +1308,6 @@ jobs: GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/markdown-linter.lock.yml@${{ github.ref }} GH_AW_INFO_VERSION: "1.0.79" 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 @@ -1379,7 +1364,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: @@ -1560,6 +1545,93 @@ jobs: } } + markdownlint: + needs: activation + runs-on: ubuntu-latest + permissions: + contents: read + timeout-minutes: 10 + 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: Install markdownlint-cli2 + id: install + run: | + status=0 + 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 ] || [ "$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)." + 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, + # 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." + if [ "$status" -eq 124 ] || [ "$status" -eq 137 ]; then + echo "The install timed out after 3 minutes." + fi + 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 + 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 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 ] || [ "$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 ] || [ "$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." + fi + echo + cat markdownlint.log + } > markdownlint.log.tmp + mv markdownlint.log.tmp markdownlint.log + fi + - 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 @@ -1585,8 +1657,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 }} @@ -1618,7 +1689,6 @@ jobs: GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/markdown-linter.lock.yml@${{ github.ref }} GH_AW_INFO_VERSION: "1.0.79" 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 @@ -1670,60 +1740,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 @@ -1750,7 +1766,6 @@ jobs: GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/markdown-linter.lock.yml@${{ github.ref }} GH_AW_INFO_VERSION: "1.0.79" 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 ff1cf14b76..c88b87fdae 100644 --- a/.github/workflows/markdown-linter.md +++ b/.github/workflows/markdown-linter.md @@ -29,57 +29,124 @@ 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 + # 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 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 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: 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. 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. + # 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. 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: | - 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" + status=0 + 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 ] || [ "$status" -eq 137 ]; then + echo "::error::Installing markdownlint-cli2@0.23.2 timed out after 3 minutes." else - echo "needs-linting=false" >> "$GITHUB_OUTPUT" + echo "::error::Installing markdownlint-cli2@0.23.2 failed (exit $status)." fi - else - echo "needs-linting=false" >> "$GITHUB_OUTPUT" + 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." + if [ "$status" -eq 124 ] || [ "$status" -eq 137 ]; then + echo "The install timed out after 3 minutes." + fi + 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. 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 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 --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 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 ] || [ "$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 ] || [ "$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." + fi + echo + cat markdownlint.log + } > markdownlint.log.tmp + mv markdownlint.log.tmp markdownlint.log fi - 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: @@ -89,7 +156,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 @@ -99,13 +166,23 @@ 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 -2. **Analyze the findings**: +1. **Read the linter output** from `/tmp/gh-aw/markdownlint.log` using the bash tool +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 - - Note: This workflow only validates Markdown files -3. **Create a detailed issue** with the following structure: + - 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. +4. **Create a detailed issue** with the following structure: ### Issue Title Use format: "Markdown Quality Report - [Date] - [X] issues found" @@ -155,7 +232,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