Chapter 22Lesson 02~210 minutes

Dependabot Alerts, Security Updates, Version Updates, Dependency Review, and Policy: Guided Hands-On Workflow and Core Operations

This lesson turns the mental model into a reproducible public-repository lab. You will establish a small lockfile, commit a bounded Dependabot policy, enable alert/security-update features explicitly, run dependency review on a real pull-request delta, and keep vulnerability simulation separate from live vulnerable code.

Disposable repodependabot.ymlDependency reviewSafe fixtureCausal evidence

Learning objectives

  • Create and verify a free-compatible npm dependency repository without running package scripts.
  • Configure bounded weekly Dependabot version updates and enable alerts/security updates separately.
  • Pin a dependency-review workflow to immutable action commits with least-privilege permissions.
  • Generate or simulate an update PR and inspect author, exact head SHA, checks, and alert state.
Availability and role. Mandatory lab: GitHub.com public personal repository, GitHub Free, repository owner/admin for security settings, write access for dependabot.yml. Exact shell snippets use Bash/Git Bash; Windows learners can run them in Git Bash, while the GitHub UI/API state is shell-independent. Dependency review is available for public repositories. The sample uses npm because its manifest/lock format is easy to inspect; the control model transfers to other supported ecosystems.
Safety. The sample intentionally uses is-number@6.0.0, an old but not intentionally vulnerable dependency, and installs lock metadata only with --ignore-scripts. Do not seed a known vulnerable package merely to manufacture an alert. If no real alert exists, use the synthetic alert fixture in this lesson.

1. Preflight: predict the hosted state before changing it

Write down these predictions: (1) committing .github/dependabot.yml will schedule version checks but will not itself enable vulnerability alerts; (2) enabling alerts/security updates changes repository security settings but does not modify Git history; (3) the dependency-review workflow will run on PRs with only contents: read; and (4) the sample package update should produce dependency-change evidence but no deliberately engineered vulnerability.

gh auth status --hostname github.com
OWNER=$(gh api -H "X-GitHub-Api-Version: 2026-03-10" user --jq .login)
REPO="$OWNER/dependabot-policy-lab"

gh repo create "$REPO" --public --add-readme --clone
cd dependabot-policy-lab
git branch --show-current
gh repo view "$REPO" --json nameWithOwner,visibility,viewerPermission,defaultBranchRef

2. Create a deterministic tiny dependency state

The lab never executes the dependency. It asks npm to create a lock file while lifecycle scripts are disabled.

cat > package.json <<'JSON'
{
  "name": "dependabot-policy-lab",
  "private": true,
  "version": "1.0.0",
  "dependencies": {
    "is-number": "6.0.0"
  }
}
JSON

npm install --package-lock-only --ignore-scripts
node -e 'const p=require("./package-lock.json"); console.log(p.packages["node_modules/is-number"].version)'

Expected local observation: the lock file records 6.0.0. The lock file is the concrete dependency state the graph and dependency-review delta can reason about.

3. Add a bounded version-update policy

version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 2
    labels:
      - "dependencies"
    groups:
      routine:
        applies-to: version-updates
        patterns:
          - "*"
mkdir -p .github/workflows
cat > .github/dependabot.yml <<'YAML'
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 2
    labels:
      - "dependencies"
    groups:
      routine:
        applies-to: version-updates
        patterns:
          - "*"
YAML

open-pull-requests-limit bounds review concurrency. The group provides a stable place to evolve grouping policy. With one dependency it is intentionally boring; production repositories often need patterns/exclusions rather than “group everything.”

4. Add dependency review as a PR admission signal

The workflow pins both GitHub-owned actions to full commit SHAs resolved at chapter generation time. A full SHA avoids silently changing executable action code while a PR is under review; update automation can propose SHA updates later.

name: Dependency review
on:
  pull_request:
permissions:
  contents: read
jobs:
  dependency-review:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout reviewed revision
        uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 line, verified 2026-08-19
        with:
          persist-credentials: false
      - name: Review dependency delta
        uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0
        with:
          fail-on-severity: high
cat > .github/workflows/dependency-review.yml <<'YAML'
name: Dependency review
on:
  pull_request:
permissions:
  contents: read
jobs:
  dependency-review:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout reviewed revision
        uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 line, verified 2026-08-19
        with:
          persist-credentials: false
      - name: Review dependency delta
        uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0
        with:
          fail-on-severity: high
YAML

git add package.json package-lock.json .github
git commit -m "Add dependency policy lab"
git push
BASE_SHA=$(git rev-parse HEAD)
printf 'baseline=%s\n' "$BASE_SHA"

This workflow needs read access to repository contents and dependency-review data; it does not need Issues, Packages, deployments, secrets, or a write token.

5. Enable/inspect alerts and security updates without hiding the state transition

In the current repository settings, open Security → Advanced Security. Confirm the dependency graph is active. Enable Dependabot alerts, then enable Dependabot security updates. These are repository security settings, so repository administrators/owners are the relevant role. Do not change organization-wide defaults for this disposable lab.

Afterward, inspect the dependency graph and the Dependabot page. Version-update status is also visible from the dependency graph/Dependabot surface after the configuration is processed.

# Read-only: version-update PRs, if Dependabot has created any.
gh pr list --repo "$REPO" --author app/dependabot --state all \
  --json number,title,state,headRefName,baseRefName,updatedAt

# Read-only alert inventory. Empty [] is a valid result for this safe lab.
gh api --paginate \
  -H "Accept: application/vnd.github+json" \
  -H "X-GitHub-Api-Version: 2026-03-10" \
  "repos/$REPO/dependabot/alerts?state=open&per_page=100" \
  --jq '.[] | {number,state,package:.dependency.package.name,severity:.security_advisory.severity,manifest:.dependency.manifest_path}'

If the API returns 403/404, distinguish feature state and alert-view permission from “there are no alerts.” An empty successful response is different from an authorization/feature failure.

6. If there is no real alert, use a synthetic alert fixture

The lab package is deliberately not chosen for a known vulnerability. Use this fixture to practice triage vocabulary without introducing exploitable code.

{
  "number": 42,
  "state": "open",
  "dependency": {
    "package": {"ecosystem": "npm", "name": "example-vulnerable-lib"},
    "manifest_path": "package-lock.json",
    "scope": "runtime",
    "relationship": "direct"
  },
  "security_advisory": {
    "ghsa_id": "GHSA-FAKE-0000-0000",
    "severity": "high",
    "summary": "Synthetic training advisory"
  },
  "security_vulnerability": {
    "vulnerable_version_range": "< 2.0.0",
    "first_patched_version": {"identifier": "2.0.0"}
  }
}

Practice the questions: Is it runtime? Direct? Is a patched version available? What tests cover the changed API? Who owns the remediation? If an exception is proposed, what evidence and expiry date will be recorded? Never dismiss a real alert merely to make a dashboard green.

7. Generate or simulate one update pull request

Dependabot may open a 6.0.0→7.0.0 PR on its own. If it does, use that PR. If scheduling has not produced a PR yet, simulate the same repository delta from a normal branch so dependency review and review policy remain testable.

BOT_PR=$(gh pr list --repo "$REPO" --author app/dependabot --state open --json number --jq '.[0].number // empty')
if [ -n "$BOT_PR" ]; then
  echo "Use Dependabot PR #$BOT_PR"
else
  git switch -c lab/dependency-update
  npm install is-number@7.0.0 --package-lock-only --ignore-scripts
  git add package.json package-lock.json
  git commit -m "Simulate dependency update to is-number 7.0.0"
  git push -u origin HEAD
  gh pr create --repo "$REPO" --base "$(gh repo view "$REPO" --json defaultBranchRef --jq .defaultBranchRef.name)" \
    --head "lab/dependency-update" \
    --title "Lab: dependency update is-number 6 to 7" \
    --body "Synthetic update PR used to exercise dependency-review policy; not created by Dependabot."
fi

Record who created the PR. A human simulation proves the dependency delta and review gate, but it does not prove Dependabot actor/secrets behavior. That distinction belongs in the evidence.

8. Observe the PR, check, and exact source state

PR=$(gh pr list --repo "$REPO" --state open --json number --jq '.[0].number')
gh pr view "$PR" --repo "$REPO" --json number,title,author,baseRefName,headRefName,headRefOid,mergeStateStatus,statusCheckRollup

gh pr checks "$PR" --repo "$REPO"

Expected evidence: the head SHA identifies the proposed dependency state, dependency review reports the delta, and ordinary merge status remains separate. If the dependency review check is made required through branch/ruleset governance, merge policy can require it; the action itself does not modify branch protection.

9. Design challenge: choose the control surface

Choose one answer for each scenario and justify it before opening the reveal below: (A) “never accept major updates to a legacy library automatically”; (B) “group patch/minor PRs for five related libraries”; (C) “block a PR that introduces a high-severity dependency”; (D) “Dependabot needs a credential for an external private npm registry.”

Scenario Correct surface
A dependabot.yml ignore/allow or explicit policy; do not rely on human memory.
B groups with narrow patterns/update types.
C Dependency-review action + required check/ruleset where desired.
D Dependabot private-registry config referencing a Dependabot secret, not an Actions secret.

Knowledge check

Why does the lab enable alerts in Settings even though dependabot.yml is committed?

Why is --ignore-scripts used while producing the lock file?

What does a successful dependency-review check prove?

Why must you record whether the PR author is Dependabot or your lab account?

The alert API returns 403. Is the correct conclusion “no vulnerabilities”?

Summary

You now have four independent pieces of evidence: committed dependency state, update configuration, repository vulnerability-feature state, and pull-request dependency review. Keeping them separate makes failures diagnosable and prevents a bot-created PR from bypassing normal review discipline.

Next you will choose update frequency/grouping, security-only versus regular version updates, auto-merge boundaries, ignore/allow policy, and private-registry credential handling based on risk rather than convenience.

Next lesson

Dependabot Alerts, Security Updates, Version Updates, Dependency Review, and Policy: Configuration, Design Choices, and Tradeoffs

Official references

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.