Skip to content

Chore(ci): add Dependabot config for weekly grouped GitHub Actions updates - #650

Open
AmaadMartin wants to merge 2 commits into
mainfrom
feat/dependabot-github-actions-updates
Open

Chore(ci): add Dependabot config for weekly grouped GitHub Actions updates#650
AmaadMartin wants to merge 2 commits into
mainfrom
feat/dependabot-github-actions-updates

Conversation

@AmaadMartin

@AmaadMartin AmaadMartin commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

  1. Link to an existing issue (if applicable):
    N/A — no existing issue tracks this; the description below applies.
  2. Or, if no issue exists, describe the change:

Problem: adk-js consumes 12 GitHub Actions uses: references (9 unique refs, 6 distinct actions) across its six workflow files, and has no .github/dependabot.yml and no renovate.json. Nothing in the repository advances those references, so an action pin only ever moves when a human notices. This is about to get worse: a separate in-flight change replaces the mutable tags with full 40-character commit SHAs, which is the right supply-chain hardening but has a well-known cost — a SHA never moves, so a pinned action freezes at whatever release it was pinned to and stops receiving upstream security and bug fixes.

Solution: Add one new file, .github/dependabot.yml, enabling Dependabot version updates for the github-actions ecosystem on a weekly schedule, with every action bump collapsed into a single grouped PR.

This is a repository-configuration-only change. It adds no TypeScript, no runtime code, no dependency, and no workflow. The entire diff is one added file, 17 insertions.

Dependabot's github-actions updater handles both reference forms this repo will have, so the config is correct today and stays correct after the SHA-pinning change lands — it is not blocked on it:

Note that Dependabot security updates for known advisories already run without any config file; what this file gates is the routine version sweep.

Collision check

Checked all 548 open PRs on the fork before writing anything:

gh pr list --repo AmaadMartin/adk-js --state open --limit 1000 --json number,title,headRefName
gh search prs --repo AmaadMartin/adk-js --state open dependabot

No open PR adds .github/dependabot.yml. Five PRs mention "dependabot" in their title or body (#505, #507, #508, #574, #613); I checked each one's file list with gh pr diff <n> --name-only and none creates the file — they touch .github/workflows/*, .nvmrc, CONTRIBUTING.md, and manifests. I also checked every open PR that touches .github/ (#403, #467, #504, #505, #507, #566, #613, #648): all of them edit existing workflow files only.

This PR therefore branches from main rather than stacking. It overlaps by adjacency with the SHA-pinning PR #505 (and its follow-up #613), but does not conflict: those PRs edit .github/workflows/* and this one adds a file neither touches. This change deliberately modifies nothing under .github/workflows/, so it can merge in either order relative to #505.

Design decisions (and rejected alternatives)

The exhaustive inventory these decisions rest on — nine uses: references, six distinct actions, verified with grep -rhoE 'uses: *[^ ]+' .github/workflows/ | sort -u at HEAD:

Action Current ref(s)
actions/checkout v3, v4, v6
actions/github-script v6, v7
actions/setup-node v6
actions/setup-go v5
actions/setup-python v5
googleapis/release-please-action v4
  1. Group pattern '*', not 'actions/*'. Five of the six distinct actions are actions/*; an actions/*-only group would leave googleapis/release-please-action to trickle in as its own separate PR for no benefit. Per the docs, dependencies matching no group rule are updated in individual PRs — with '*' there are no stragglers, and the steady state is exactly one PR per week.
  2. open-pull-requests-limit omitted. The documented default is 5. Because the '*' group collapses all bumps into a single PR, the practical steady state is one open PR, so an explicit limit would restate the default without changing behaviour. Omitting it keeps the file to only the keys that actually decide something.
  3. commit-message.prefix: 'chore(deps)' included. Without it Dependabot infers a prefix from commit history, which here is mixed (fix(core):, Feat:, chore(ci):) and so unpredictable. release-please-config.json declares "release-type": "node", which parses conventional commits to build releases; pinning a chore scope guarantees CI-only bumps never generate a release entry. It also matches existing precedent in this repo's history (fix(deps): declare dotenv in the workspace root manifest, Chore(deps): add @langchain/core and @langchain/langgraph as optional peers).
  4. npm and gomod ecosystems are out of scope. Adding them is a materially larger and more debatable decision (566 KB lockfile, three workspaces, Go test clients) and belongs in its own change.
  5. No labels, assignees, reviewers, target-branch, ignore, or cooldown keys. Each would either restate a default or encode a policy nobody asked for. Dependabot applies its default dependencies label already.

Style note: the file uses single-quoted scalars to match the existing convention under .github/workflows/ (go-version: '1.25', python-version: '3.11', name: 'CSAT survey ADK JS'), even though GitHub's published examples use double quotes. This is stylistic only; both parse identically. The file complies with .editorconfig (2-space indent, LF, UTF-8, trailing newline) and carries no license headerscripts/check_license.sh scans only *.js/*.ts, and no existing file under .github/ has one.

Testing Plan

Please describe the tests that you ran to verify your changes. This is required for all PRs that are not small documentation or typo fixes.
Unit Tests:
[ ] I have added or updated unit tests for my change. — deliberately not applicable, justified below.
[ ] All unit tests pass locally. — not run: this change adds no executable code and no test targets it. Per the repo's targeted-testing guidance I ran only the checks that actually exercise the change (below), not the full suite.

No *_test.ts file was added, and that is a deliberate decision rather than an oversight. There are zero new lines of executable code, so there is no line, branch, or function coverage to add. The vitest coverage scope is core/src/**, dev/src/**, integrations/src/** (see vitest.config.ts); a file under .github/ is outside it and the coverage thresholds are unaffected. No repository-configuration test exists anywhere in core/test/, dev/test/, integrations/test/, or tests/ — adding one would invent a new test category and would assert GitHub's schema rather than any adk-js behaviour.

In place of unit tests I ran three deterministic local checks, and proved each one can fail by mutating the file.

Check 1 — the file parses as YAML (uses js-yaml, already a declared dependency of core and dev at ^4.1.1; nothing was installed and neither package.json nor package-lock.json was touched):

$ npx js-yaml .github/dependabot.yml
{
  "version": 2,
  "updates": [
    {
      "package-ecosystem": "github-actions",
      "directory": "/",
      "schedule": { "interval": "weekly" },
      "groups": { "github-actions": { "patterns": ["*"] } },
      "commit-message": { "prefix": "chore(deps)" }
    }
  ]
}
exit=0

Check 2 — the parsed shape matches the Dependabot v2 schema for this ecosystem:

$ node --input-type=module -e "
import {readFileSync} from 'node:fs';
import yaml from 'js-yaml';
import assert from 'node:assert/strict';
const c = yaml.load(readFileSync('.github/dependabot.yml', 'utf8'));
assert.equal(c.version, 2);
assert.equal(c.updates.length, 1);
const u = c.updates[0];
assert.equal(u['package-ecosystem'], 'github-actions');
assert.equal(u.directory, '/');
assert.equal(u.schedule.interval, 'weekly');
assert.deepEqual(u.groups['github-actions'].patterns, ['*']);
assert.equal(u['commit-message'].prefix, 'chore(deps)');
console.log('dependabot.yml OK');
"
dependabot.yml OK

Check 3 — validated against the published Dependabot JSON Schema. ajv-cli was run as a throwaway npx --yes invocation; no dependency was added to package.json. Two non-obvious details: ajv-cli cannot fetch -s from a URL, so the schema is downloaded first; and --strict=false is required because the published schema carries the vendor keyword x-intellij-enum-metadata, which ajv's strict mode rejects — that failure is a property of the schema, not of this config.

$ curl -sL https://json.schemastore.org/dependabot-2.0.json -o /tmp/dependabot-schema.json
$ npx --yes ajv-cli@5 validate -s /tmp/dependabot-schema.json \
    -d .github/dependabot.yml --spec=draft7 --strict=false
.github/dependabot.yml valid

Proving the checks can fail (mutation testing)

Three mutations were applied to the committed file and then fully reverted (diff against a pristine copy confirms the committed file is byte-identical to the pre-mutation version; all three checks were re-run green afterwards).

# Mutation Result
A directory: '/''/.github/workflows' Check 2 FAILS, check 3 still passes
B version: 2version: 3 Check 3 FAILS
C package-ecosystem: 'github-actions''github-action' Check 3 FAILS

Mutation A is the important one. /.github/workflows is the plausible wrong value, and it is the quiet failure mode: the config stays valid but matches no manifests, so Dependabot silently opens nothing. Failure message:

AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
  actual:   '/.github/workflows',
  expected: '/',

Under mutation A, ajv still reported .github/dependabot.yml valid — the schema types directory as a plain string with no constraint. That is precisely why check 2 exists rather than relying on schema validation alone, and why the directory === '/' assertion is the one with real signal. Per the docs: "For GitHub Actions, use the value /. Dependabot will search the /.github/workflows directory, as well as the action.yml/action.yaml file from the root directory."

Mutations B and C exist to prove check 3 is not a rubber stamp, and to ground the two literal values it validates. B: must be equal to constant. C: must be equal to one of the allowed values — confirming github-actions is a real enum member of the published schema rather than a value written from memory.

CI impact, verified rather than assumed. validation.yaml runs npx secretlint "**/*", which is the only CI step that scans this file. Run against the new file with the repo's own .secretlintrc.json: exit 0, no findings (the file contains no credentials, and no token or registry stanza was added). scripts/check_license.sh passes — run locally, and it scans only *.js/*.ts so the new YAML is not considered. npm run lint (eslint "**/*.ts"), npm run format:check (prettier "**/*.ts" --check), build, test:coverage, and docs:check are all TypeScript-scoped and cannot see this file; prettier was deliberately not run against it. cross-language-integration.yml is untouched.

Diff hygiene, verified:

$ git diff <base> --stat
 .github/dependabot.yml | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

Nothing under .github/workflows/ is modified, package.json and package-lock.json are untouched, no suppressions (any, @ts-expect-error, eslint-disable) are introduced, and no CHANGELOG.md or patch artifacts appear.

Manual End-to-End (E2E) Tests:
Please provide instructions on how to manually test your changes, including any necessary setup or configuration.

This cannot be completed from a pull-request branch, by construction. Dependabot reads .github/dependabot.yml from the repository's default branch only, and version updates are not enabled automatically on forks — a fork owner must turn them on explicitly under Settings → Advanced Security → Dependabot → Dependabot version updates → Enable. The three checks above are the pre-merge substitute.

Post-merge acceptance step, for a maintainer (or for the fork owner on a fork whose default branch carries the file):

  1. Ensure Dependabot version updates are enabled for the repository (required explicitly on forks).
  2. With the file on the default branch, open Insights → Dependency graph → Dependabot.
  3. Expect a github-actions row with a "Last checked" timestamp and no configuration-error banner. A red banner there is the single authoritative signal that the file is wrong.
  4. Expect the first grouped PR within a week, titled approximately chore(deps): bump the github-actions group with N updates. Dependabot applies a default 3-day cooldown to version updates, so a very recently released action version may not appear in the first sweep — that is expected, not a configuration fault.

To revert: delete the file. To pause without deleting: set open-pull-requests-limit: 0.

Checklist

[x] I have read the CONTRIBUTING.md document.
[x] I have performed a self-review of my own code.
[x] I have commented my code, particularly in hard-to-understand areas.
[ ] I have added tests that prove my fix is effective or that my feature works. — no test file added (zero new executable lines); replaced by three mutation-proven verification checks, justified in the Testing Plan.
[ ] New and existing unit tests pass locally with my changes. — the repo unit suite was not run; no test targets this change.

CI result on this PR

All checks green on the revised commit 2c00a348, including the real test jobs (not just the trivial ones):

Check Result
run-tests (ubuntu-latest) pass — 5m29s
run-tests (macos-latest) pass — 4m36s
run-tests (windows-latest) pass — 9m15s
run-tests (cross-language) pass — 1m40s
check-license pass

Revision after complexity review

A complexity reviewer flagged the file's comments (not its configuration). Both findings were valid and are fixed in Chore(ci): trim speculative and redundant comments from the Dependabot config:

  1. Deleted the four-line header narration describing how Dependabot advances commit-SHA pins. Verified the reviewer's premise before acting: grep -rhoE 'uses: *[^ ]+@[0-9a-f]{40}' .github/workflows/ returns nothing — every uses: reference at HEAD is a tag pin, so the comment hedged against a repo state that does not exist. The SHA-pin rationale is real and still matters, but it belongs in this PR description (above), not in the file. Kept the one-line purpose statement and the schema link.
  2. Collapsed the two-line commit-message comment to one line. Same information, one line.

The comment on directory: '/' was explicitly kept — it documents the genuine footgun that / means .github/workflows for this ecosystem, which is exactly what mutation A below proves is worth guarding.

Net −4 lines: 21 → 17. The change is comments only, and this was verified rather than assumed — the parsed output of the before and after files is byte-identical:

$ npx js-yaml <old> > /tmp/before.json; npx js-yaml .github/dependabot.yml > /tmp/after.json
$ diff /tmp/before.json /tmp/after.json
(no output — identical parsed output, zero functional change)

All checks were re-run green on the revised file: check 1 (YAML parse), check 2 (shape assertion), check 3 (ajv.github/dependabot.yml valid), secretlint (exit 0), and scripts/check_license.sh. Mutation A was re-applied to the revised file to confirm the revision did not weaken the checks — check 2 still fails with actual: '/.github/workflows', expected: '/' — then fully reverted, with the file verified byte-identical to its pre-mutation state.

Amaad Martin added 2 commits August 4, 2026 11:21
…dates

adk-js has no .github/dependabot.yml and no renovate.json, so nothing in the
repository advances the action references in .github/workflows. Enable
Dependabot version updates for the github-actions ecosystem on a weekly
schedule, collapsing every action bump into one grouped pull request.

The updater handles both reference forms the repo will have: today's mutable
tag pins, and the commit-SHA pins an in-flight change introduces (Dependabot
rewrites the trailing version comment alongside the SHA).

Group pattern is '*' rather than 'actions/*': five of the six actions the
workflows consume are actions/*, and an actions/*-only group would leave
googleapis/release-please-action to trickle in as a separate PR. The explicit
chore(deps) commit prefix keeps release-please from treating CI-only bumps as
releasable changes.
…t config

Drop the header narration describing how Dependabot advances commit-SHA pins.
Every uses: reference in .github/workflows is a tag pin at HEAD, so the comment
hedged against a repo state that does not exist; the rationale for why the
config also covers SHA pins belongs in the pull request description, not the
file. Collapse the two-line commit-message comment to one line.

Comments only: the parsed configuration is byte-identical.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant