Skip to content

Ignore Dependabot security updates in the failure watcher - #71

Merged
oschwald merged 1 commit into
mainfrom
wstorey/stf-1245-dependabot-failure-watcher-emails-go-to-the-correct-person
Jul 30, 2026
Merged

Ignore Dependabot security updates in the failure watcher#71
oschwald merged 1 commit into
mainfrom
wstorey/stf-1245-dependabot-failure-watcher-emails-go-to-the-correct-person

Conversation

@horgh

@horgh horgh commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

GitHub runs Dependabot version updates and Dependabot security updates under one
workflow name, Dependabot Updates, and the watcher counted both. Security
updates routinely fail for reasons no pull request can fix, so the watcher went
red on its first scheduled run with 41 unactionable failures and would have
stayed red every week.

This filters security-update runs out by title, documents why both halves of
" in /. for " are load-bearing, and bounds the gh run list query
server-side with --created instead of fetching all of history.

See the commit message for the full reasoning, including why reading the
directory list out of dependabot.yml was tried and rejected.

This same change is being applied to the other 42 MaxMind repos that share this
workflow.

Summary by CodeRabbit

  • Bug Fixes
    • Improved detection of failed automated dependency update runs.
    • Filters out security-update-like runs and end-to-end test directories to reduce false alerts.
    • Reports matching failures with clearer titles and links, while providing an updated all-clear message when no failures are found.

Copilot AI review requested due to automatic review settings July 30, 2026 16:55
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@horgh, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 8 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 77841b66-e358-4093-b5bc-a48f81fa5d69

📥 Commits

Reviewing files that changed from the base of the PR and between 2ac6f28 and aa55310.

📒 Files selected for processing (1)
  • .github/workflows/dependabot-failure-watcher.yml
📝 Walkthrough

Walkthrough

The Dependabot failure watcher now documents run-title filtering rules and queries recent runs server-side. It excludes specified security and end-to-end update categories, reports selected failure conclusions, and updates its success and failure messages.

Changes

Dependabot failure filtering

Layer / File(s) Summary
Document and implement Dependabot failure detection
.github/workflows/dependabot-failure-watcher.yml
Expanded filtering documentation and rewrote the workflow step to query recent runs, exclude selected title patterns, detect failure conclusions, and print updated status messages.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: copilot

Poem

A rabbit watched the Dependabot trail,
Sorting each run by its title and tale.
E2E hops aside,
Failed updates can’t hide—
Clear skies when no failures prevail.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: the failure watcher now ignores Dependabot security updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch wstorey/stf-1245-dependabot-failure-watcher-emails-go-to-the-correct-person

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the “Dependabot Failure Watcher” GitHub Actions workflow so it only reports actionable failures (Dependabot version update runs) and ignores Dependabot security update runs that commonly fail for reasons unrelated to the repository’s health.

Changes:

  • Excludes security-update workflow runs by filtering gh run list results based on displayTitle.
  • Bounds the GitHub CLI query server-side using gh run list --created to avoid fetching full history.
  • Expands and clarifies in-file documentation describing the different Dependabot run types and why the title-matching is intentionally precise.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/dependabot-failure-watcher.yml:
- Around line 93-98: Update the workflow-run query in the runs collection to use
the 1,000-result limit, then fail closed when the fetched run count reaches that
cap before evaluating the all-clear result. Preserve the existing repository,
workflow, and since-date filters, and ensure the failure clearly indicates that
the query may have hit GitHub’s search cap.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 710decf8-cd74-4ff1-9604-1cf7ff11a9b5

📥 Commits

Reviewing files that changed from the base of the PR and between c614d66 and 2ac6f28.

📒 Files selected for processing (1)
  • .github/workflows/dependabot-failure-watcher.yml

Comment on lines +93 to +98
runs=$(gh run list \
--repo "$REPO" \
--workflow "Dependabot Updates" \
--limit 100 \
--json conclusion,createdAt,displayTitle,url \
--jq "[.[] | select((.conclusion == \"failure\" or .conclusion == \"startup_failure\" or .conclusion == \"timed_out\") and .createdAt >= \"$since\")]")
--created ">=$since" \
--limit 500 \
--json conclusion,createdAt,displayTitle,url)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "File size:"
wc -l .github/workflows/dependabot-failure-watcher.yml

echo
echo "Relevant workflow lines:"
cat -n .github/workflows/dependabot-failure-watcher.yml | sed -n '80,145p'

echo
echo "Search run list usage and failure handling:"
rg -n "run list|total_count|--limit|fail|alert|error|all-clear|Dependabot Updates" .github/workflows/dependabot-failure-watcher.yml

Repository: maxmind/device-android

Length of output: 3939


🌐 Web query:

GitHub REST API workflow runs created query max results 1000 totalCount

💡 Result:

When using the GitHub REST API to list workflow runs, endpoints such as List workflow runs for a repository or List workflow runs for a workflow are subject to a search result limit [1][2][3]. Specifically, these endpoints return a maximum of 1,000 results when applying filters such as actor, branch, check_suite_id, created, event, head_sha, or status [1][2][3]. While the API response includes a total_count field, which indicates the total number of items available, you cannot paginate beyond the 1,000-result threshold using standard page-based parameters [1][2][3]. If your query would return more than 1,000 runs, you must further narrow your results using additional filters (e.g., more specific created date ranges) to access the remaining data [1][2][3]. Standard pagination (using per_page and page parameters) remains available for the initial 1,000 results, with per_page capped at a maximum of 100 items per request [1][2][4]. For large datasets, developers typically use octokit.paginate or manual iterative requests to handle pagination up to that limit [4].

Citations:


🌐 Web query:

GitHub CLI gh run list workflow status limit 1000 totalCount

💡 Result:

The GitHub CLI (gh) command gh run list does not support a totalCount output field, nor does it provide a native way to retrieve an aggregate count of all workflow runs [1]. Key points regarding your query: 1. Limit Flag: The --limit (-L) flag is used to specify the maximum number of workflow runs to fetch [2][3]. While you can set this number as high as you like (e.g., --limit 1000), it functions as a cap for the number of items returned in the current request [1]. It does not retrieve a global total count of runs [1]. 2. No totalCount: The gh run list command does not expose a totalCount field in its output or via the --json flag [1]. 3. Fetching All Runs: There is currently no built-in functionality in gh run list to automatically fetch all workflow runs or to return the total count of existing runs [4]. If you require a true total count, the recommended approach is to use the GitHub REST or GraphQL API directly via the gh api command [1]. For example, querying the repository's actions/runs endpoint via the API allows for more granular control over pagination and metadata [5]. In summary, you cannot use --limit 1000 to get a totalCount; you can only use it to increase the number of items returned in your CLI output [2][1].

Citations:


Fail closed when the workflow-run query hits its search cap.

--limit 500 is below the GitHub REST search cap of 1,000, and with more than 1,000 matching Dependabot runs the response cannot return all results, so the final all-clear can hide older failures. Use a 1,000 limit and fail if the fetched count reaches that cap, or otherwise narrow the query/date range.

Proposed safeguard
-            --limit 500 \
+            --limit 1000 \

+          fetched_count=$(echo "$runs" | jq 'length')
+          if [ "$fetched_count" -ge 1000 ]; then
+            echo "::error::Dependabot run query reached its limit; refusing to report all-clear."
+            exit 1
+          fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
runs=$(gh run list \
--repo "$REPO" \
--workflow "Dependabot Updates" \
--limit 100 \
--json conclusion,createdAt,displayTitle,url \
--jq "[.[] | select((.conclusion == \"failure\" or .conclusion == \"startup_failure\" or .conclusion == \"timed_out\") and .createdAt >= \"$since\")]")
--created ">=$since" \
--limit 500 \
--json conclusion,createdAt,displayTitle,url)
runs=$(gh run list \
--repo "$REPO" \
--workflow "Dependabot Updates" \
--created ">=$since" \
--limit 1000 \
--json conclusion,createdAt,displayTitle,url)
fetched_count=$(echo "$runs" | jq 'length')
if [ "$fetched_count" -ge 1000 ]; then
echo "::error::Dependabot run query reached its limit; refusing to report all-clear."
exit 1
fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/dependabot-failure-watcher.yml around lines 93 - 98,
Update the workflow-run query in the runs collection to use the 1,000-result
limit, then fail closed when the fetched run count reaches that cap before
evaluating the all-clear result. Preserve the existing repository, workflow, and
since-date filters, and ensure the failure clearly indicates that the query may
have hit GitHub’s search cap.

Source: MCP tools

GitHub runs both Dependabot version updates and Dependabot security
updates under one workflow name, "Dependabot Updates", and the watcher
counted both. Security updates routinely fail for reasons no pull
request can fix -- the advisory is against a dependency this project
does not declare directly, or no patched version is reachable -- so the
watcher went red on its first scheduled run with 41 such failures, none
of which were actionable. Left alone it would stay red every week and
train everyone to ignore it.

Filter those runs out by title. Version updates are unaffected: over the
repo's full retained Dependabot history this drops all 223 security jobs
while still reporting the two genuine gradle version-update failures
from 2025-12-10.

The title check is subtler than it looks, so document it properly. A
security job is marked by "/." AND a " for " suffix together; version
updates are either "/." with no " for " (the scheduled scan) or "/" with
one (the pull request). Both halves of " in /. for " are therefore
load-bearing -- matching on " in /." alone would discard every scan run,
which is most of the version-update runs and the shape both 2025-12-10
failures took.

That "/." spelling only separates the two at the repo root. In a
subdirectory a security update and a version update's pull request
render identically, so drop " in /e2e/{js,ts} for " by name as well. The
Node repos this workflow is shared with carry committed lockfiles under
e2e/js and e2e/ts, whose transitive dev dependencies attract advisories
no pull request can fix, and nothing in either is shipped code. That is
16 unactionable failures in each of GeoIP2-node and minfraud-api-node
over retained history; device-android, geoip-splunk and both dotnet
repos have no such directories and are unaffected.

Unlike the root filter, this one is not free. Both Node repos configure
npm with directories: ["/", "**/*"], and that glob does match e2e/js and
e2e/ts, so those directories do get version updates -- there is an open
version-update pull request under e2e/ts in both repos as this is
written. Dropping the pattern discards their pull-request refresh
failures along with the security jobs, and the ecosystem label is no
help because Dependabot writes "npm_and_yarn" for both. Taken anyway:
the scheduled scan is what this watcher primarily exists to catch and is
still reported for those directories, so what is given up is the
narrower "one open pull request has gone stale" signal for two
directories of test scaffolding. After filtering, 4 genuine failures
remain reported in GeoIP2-node and 3 in minfraud-api-node.

Reading the directories out of dependabot.yml would look more general
and was the earlier plan here, but it fails green. Entries may use
globs, and minfraud-api-dotnet's directories: ["**/*"] yields titles
like "nuget in /**/*" for the scan and "nuget in /MaxMind.MinFraud for
System.Net.Http.Json" for the pull request, neither of which any literal
comparison against the configured value matches -- so its two real nuget
failures would have been dropped without a word. A stale denylist
re-introduces noise, which is loud; a stale allowlist hides failures.

Name the three kinds of run in the comment while here, because the
scheduled scan and the per-pull-request refresh are easy to conflate:
the refresh runs are one per open pull request and are triggered by
pushes to the base branch or by rebases, not by the schedule, so they
arrive in bursts after merges. The scan is the kind this watcher
primarily exists to catch, which is what makes hiding a hypothetical
refresh failure under e2e an acceptable cost rather than a hole.

Bound the query server-side with --created instead of fetching all of
history and filtering by date locally. That takes this repo's fetch from
399 runs to 47, so --limit now caps an already-narrowed window rather
than standing in for one, and the run list drops from five API pages to
one. --limit rises 100 -> 500 as a backstop: it still applies before the
title filter, and reaching it would silently drop the oldest in-window
runs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@horgh
horgh force-pushed the wstorey/stf-1245-dependabot-failure-watcher-emails-go-to-the-correct-person branch from 2ac6f28 to aa55310 Compare July 30, 2026 17:46
@oschwald
oschwald merged commit 86602ef into main Jul 30, 2026
11 checks passed
@oschwald
oschwald deleted the wstorey/stf-1245-dependabot-failure-watcher-emails-go-to-the-correct-person branch July 30, 2026 18:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants