Skip to content

Feature/scala steward / dependabot cooldown#25

Open
marcin-jozefowicz wants to merge 2 commits into
mainfrom
feature/scala-steward-cooldown
Open

Feature/scala steward / dependabot cooldown#25
marcin-jozefowicz wants to merge 2 commits into
mainfrom
feature/scala-steward-cooldown

Conversation

@marcin-jozefowicz

@marcin-jozefowicz marcin-jozefowicz commented Jul 20, 2026

Copy link
Copy Markdown

Supply-chain cooldown for Scala Steward + Dependabot

Introduces a cooldown (maturation delay) so new dependency versions aren't adopted the moment they're published — a compromised release has time to be detected first. Security updates (GHSA/CVE advisories) are unaffected and stay fast. Two independent parts, one per toolchain.


Scala Steward (Scala repos)

What: a central default.scala-steward.conf with updates.cooldown.minimumAge = "3 days", wired into the reusable scala-steward.yml (sparse-checkout of this repo, passed as repo-config).

How it works:

  • Applies to every repo that already calls the reusable scala-steward.ymlno per-repo change needed.
  • A repo's own .scala-steward.conf (pins/ignores/overrides) is still auto-discovered and deep-merged per field on top, so local settings keep working alongside the central cooldown.
  • No new credentials — runs with the existing token.

Dependabot (non-Scala repos)

1. Overview & rationale

Adds a central, self-maintaining workflow (.github/workflows/dependabot-cooldown.yml) that enforces the cooldown on the org's Dependabot configs.

  • Dependabot has no org-wide config — the cooldown must live in each repo's committed .github/dependabot.yml.
  • Discovery, not a hand-kept list — the fleet has ~20 repos with a Dependabot config, and the set changes. The workflow finds them at runtime instead of maintaining a list or a caller per repo.
  • Surgical patch — it sets only cooldown.default-days on every updates: entry via yq, preserving comments, key order, and sibling keys. Strict: the central value wins over any local one.

2. Prerequisites — one-time GitHub App setup (org admin)

The workflow writes to other repos, which GITHUB_TOKEN can't. A GitHub App is used instead; its private key is the only standing secret, and every token it mints is short-lived (~1h) and repo-scoped.

  1. Register a GitHub App in the org (e.g. sml-dependabot-cooldown); webhook off.
  2. Permissions: Contents R/W, Pull requests R/W, Metadata R/O.
  3. Generate + download the private key (.pem).
  4. Install it on the target repos (App page → Install → softwaremill). The App can only discover and patch repos it is installed on, so this step defines the fleet: pick All repositories (self-maintaining as new repos appear; the workflow's filters narrow it) or Only select repositories (tighter, but a list you maintain).
  5. In this repo → Settings → Actions: variable DEPENDABOT_COOLDOWN_APP_CLIENT_ID (client ID) + secret DEPENDABOT_COOLDOWN_APP_KEY (full .pem).

3. How it works

  1. discover — mints an org-scoped App token, lists the App's installed repos, keeps active (non-archived, non-fork) ones that actually have a Dependabot config, minus the EXCLUDE list → emits a matrix.
  2. patch — one job per repo: mints a repo-scoped App token, patches cooldown.default-days, and opens a PR on a fixed branch (chore/dependabot-cooldown, force-pushed so re-runs update the same PR).

PRs are opened with the App token, so the target repo's CI runs on them (unlike GITHUB_TOKEN). PRs are left for review — not auto-merged. A repo with no Dependabot config is a no-op.

4. Triggering

  • Schedule: weekly, re-applies the policy and picks up newly added configs.

  • Manual (workflow_dispatch, from this repo's Actions tab):

    Input Description Default
    cooldown-days Cooldown in days (retune the fleet) 3
    repos Explicit repo list to patch instead of discovery

Testing & rollout

yq patch verified (Docker mikefarah/yq:v4.53.3, the runner's version): the exact expression writes default-days as an unquoted int, only the target line changes (comments/order/siblings preserved), and an existing value is overwritten. Surgical + strict, as intended.

Rollout: start scoped — workflow_dispatch with repos: '<one-repo>', check the PR, then re-run unscoped. Narrow further via Select repositories install or the EXCLUDE list.

Introduce a central default.scala-steward.conf carrying a 3-day
supply-chain cooldown (updates.cooldown.minimumAge) and wire it into the
reusable scala-steward workflow via a sparse checkout, passed as
repo-config. Per-repo .scala-steward.conf (pins/ignores) is still
auto-discovered and deep-merged on top, taking precedence per field.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A central, self-maintaining workflow in this repo that enforces a
supply-chain cooldown across the org's Dependabot configs. Dependabot has
no org-wide config, so a cooldown block must live in each repo's committed
.github/dependabot.yml. The workflow discovers target repos via a GitHub
App installation (active, non-fork repos that carry a Dependabot config),
then fans out a matrix: one job per repo mints a short-lived, repo-scoped
App token, patches cooldown.default-days on every updates: entry, and opens
a PR.

The patch is surgical (per updates: entry, preserving comments and key
order) and strict (the central value wins over any local one). PRs are
opened with the App token so the target repo's CI runs on them, and are
left for review (no auto-merge). Requires a GitHub App exposed as
vars.DEPENDABOT_COOLDOWN_APP_CLIENT_ID and secrets.DEPENDABOT_COOLDOWN_APP_KEY.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@marcin-jozefowicz
marcin-jozefowicz force-pushed the feature/scala-steward-cooldown branch from 483a2a4 to e936d7f Compare July 21, 2026 09:55
@marcin-jozefowicz
marcin-jozefowicz marked this pull request as ready for review July 21, 2026 11:50
@marcin-jozefowicz marcin-jozefowicz changed the title [DRAFT] Feature/scala steward / dependabot cooldown Feature/scala steward / dependabot cooldown Jul 21, 2026
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