Skip to content

ci(dependabot): target dev for all update ecosystems - #14

Open
singlerider wants to merge 2 commits into
blacklanternsecurity:devfrom
singlerider:ci/dependabot-target-dev
Open

singlerider wants to merge 2 commits into
blacklanternsecurity:devfrom
singlerider:ci/dependabot-target-dev

Conversation

@singlerider

Copy link
Copy Markdown
Contributor

Without target-branch, Dependabot opens every update against the default branch, so bumps land on the release branch instead of dev and get closed by hand.

Dependabot only reads dependabot.yml from the default branch, so this targets it directly.

Related (closed, opened against the default branch): none yet; preventive, matching the org pattern

Validated: python -c "import yaml; yaml.safe_load(open('.github/dependabot.yml'))" parses cleanly.

en0f and others added 2 commits November 9, 2026 10:32
Without target-branch, Dependabot opens every update against the
default branch, so bumps land on the release branch instead of dev
and have to be closed by hand. Dependabot only reads this file from
the default branch, so the fix has to land there to take effect.
@singlerider
singlerider requested a review from a team as a code owner November 9, 2026 17:27

@en0f en0f left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed at 6cacec4.

🔴 Targets stable instead of dev

This PR goes from a feature branch straight into stable. The README (How changes land) says stable takes a pull request from dev, the org CONTRIBUTING says to open pull requests against dev, and every PR merged into stable so far (#3, #6, #8, #12) came from dev. You're right that Dependabot only reads dependabot.yml from the default branch, but that just means the line takes effect with the next release. Retarget with gh pr edit 14 --base dev. The diff will also show merge commit 1213919 from stable, which carries no content.

🔴 Validation doesn't show Dependabot opening a PR against dev

The validation shows the file parses, not that Dependabot opens its update PRs against dev, which is the point of the change. git.md (Pull requests) asks for the commands run and their real output. On your fork, enable Dependabot version updates with this dependabot.yml on the fork's default branch, and paste the PR it opens with base dev, for example gh pr list --repo <fork> --author app/dependabot --json number,baseRefName.

Reproduce this review
# save the script below as verify-14.sh, then:
bash verify-14.sh blacklanternsecurity/release-workflows 6cacec4276ec2999f379292ac3e70bf36a4122c2
# expected: SUMMARY 4 PASS, 2 FAIL, 0 SKIP, 0 BROKEN
# control:  bash verify-14.sh blacklanternsecurity/release-workflows 12139195c6f35d8b4478bb8ec3df94aa275da01e   -> V01=FAIL
#!/usr/bin/env bash
# verify-14.sh: reproducible checks for blacklanternsecurity/release-workflows#14
# Usage: bash verify-14.sh <owner/repo> <sha> [<control-patch>]
# Changes nothing outside a mktemp directory and nothing on GitHub (PR-VF-02).
# V03-V06 read GitHub state through gh api --method GET; rerun them after the PR changes.
#
# CONTROL: sha 12139195c6f35d8b4478bb8ec3df94aa275da01e
# CONTROL-EXPECT: V01=FAIL
set -uo pipefail

REPO="${1:?owner/repo}"; SHA="${2:?sha}"; PATCH="${3:-}"
PR=14
PASS=0; FAIL=0; SKIP=0; BROKEN=0
pass()   { echo "PASS $1 $2"; PASS=$((PASS+1)); }
fail()   { echo "FAIL $1 $2 -- $3"; FAIL=$((FAIL+1)); }
skip()   { echo "SKIP $1 $2 -- $3"; SKIP=$((SKIP+1)); }
broken() { echo "BROKEN $1 $2 -- $3"; BROKEN=$((BROKEN+1)); }
summary() { echo "SUMMARY $PASS PASS, $FAIL FAIL, $SKIP SKIP, $BROKEN BROKEN"; [ "$FAIL" -eq 0 ] && [ "$BROKEN" -eq 0 ]; }

echo "script_sha256 $(shasum -a 256 "$0" | cut -d' ' -f1)"
echo "git $(git --version | cut -d' ' -f3)"
echo "gh $(gh --version | head -1 | cut -d' ' -f3)"
echo "jq $(jq --version)"

WORK="$(mktemp -d)"; trap 'rm -rf "$WORK"' EXIT
export GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1 GIT_TERMINAL_PROMPT=0
GIT=(git -c credential.helper= -c 'credential.helper=!gh auth git-credential')
"${GIT[@]}" clone --quiet --filter=blob:none --no-checkout "https://github.com/$REPO.git" "$WORK/src" || { broken V00 "clone" "clone failed"; summary; exit 1; }
cd "$WORK/src"
"${GIT[@]}" cat-file -e "$SHA^{commit}" 2>/dev/null || "${GIT[@]}" fetch --quiet origin "+refs/pull/*/head:refs/remotes/pr/*" || true
"${GIT[@]}" checkout --quiet --detach "$SHA" || { broken V00 "checkout $SHA" "checkout failed"; summary; exit 1; }
[ "$(git rev-parse HEAD)" = "$SHA" ] || { broken V00 "HEAD is $SHA" "HEAD mismatch"; summary; exit 1; }
if [ -n "$PATCH" ]; then git apply "$PATCH" || { broken V00 "apply control patch" "git apply failed"; summary; exit 1; }; fi
GET() { gh api --method GET "$@"; }

# ---- checks: each line states the desired property --------------------------
# V01: every Dependabot update entry targets dev.
F=.github/dependabot.yml
if [ ! -f "$F" ]; then broken V01 "every dependabot update entry sets target-branch: dev" "$F missing"
else
  ECO=$(grep -cE '^[[:space:]]*-[[:space:]]+package-ecosystem:' "$F")
  TGT=$(grep -cE '^[[:space:]]+target-branch:[[:space:]]*"?dev"?[[:space:]]*$' "$F")
  if [ "$ECO" -gt 0 ] && [ "$ECO" -eq "$TGT" ]; then pass V01 "every dependabot update entry sets target-branch: dev ($TGT/$ECO)"
  else fail V01 "every dependabot update entry sets target-branch: dev" "$TGT of $ECO entries"; fi
fi

# V02: the branch Dependabot is pointed at exists.
if GET "repos/$REPO/branches/dev" --jq .name >/dev/null 2>&1; then pass V02 "branch dev exists"
else fail V02 "branch dev exists" "GET branches/dev failed"; fi

# V03: the PR targets dev (README.md, How changes land: stable takes pull requests from dev).
BASE_REF=$(GET "repos/$REPO/pulls/$PR" --jq .base.ref 2>/dev/null) || BASE_REF=""
if [ -z "$BASE_REF" ]; then broken V03 "PR #$PR targets dev" "could not read the PR"
elif [ "$BASE_REF" = dev ]; then pass V03 "PR #$PR targets dev"
else fail V03 "PR #$PR targets dev" "base is $BASE_REF"; fi

# V04: every merged pull request into stable came from dev (the precedent the README rule describes).
OTHER=$(GET "repos/$REPO/pulls?state=closed&base=stable&per_page=100" --jq '[.[]|select(.merged_at!=null and .head.ref!="dev")|.number]|length' 2>/dev/null) || OTHER=""
if [ -z "$OTHER" ]; then broken V04 "every merged PR into stable came from dev" "could not list PRs"
elif [ "$OTHER" -eq 0 ]; then pass V04 "every merged PR into stable came from dev"
else fail V04 "every merged PR into stable came from dev" "$OTHER did not"; fi

# V05: Dependabot has opened at least one pull request in this repository (the outcome the PR configures).
DB=$(GET "repos/$REPO/pulls?state=all&per_page=100" --jq '[.[]|select(.user.login=="dependabot[bot]")]|length' 2>/dev/null) || DB=""
if [ -z "$DB" ]; then broken V05 "dependabot has opened a PR in $REPO" "could not list PRs"
elif [ "$DB" -gt 0 ]; then pass V05 "dependabot has opened a PR in $REPO ($DB)"
else fail V05 "dependabot has opened a PR in $REPO" "0 PRs by dependabot[bot], although its run of 2026-11-04 (actions run 41886869590) logged 'Creating a pull request for github-actions'"; fi

# V06: a merge to stable at this version publishes nothing (v<version> already tagged, release-check.yml sets release=false).
VER=$(sed -nE 's/^version = "([^"]+)"/\1/p' pyproject.toml | head -1)
if [ -z "$VER" ]; then broken V06 "v<version> already tagged" "no version in pyproject.toml"
elif GET "repos/$REPO/git/ref/tags/v$VER" --jq .ref >/dev/null 2>&1; then pass V06 "v$VER already tagged, so a merge to stable publishes nothing"
else fail V06 "v$VER already tagged" "tag v$VER not found"; fi
# ------------------------------------------------------------------------------
summary

Comment thread .github/dependabot.yml Resolved
@singlerider
singlerider changed the base branch from stable to dev November 9, 2026 19:41

This branch has not been deployed

No deployments
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.

2 participants