Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/add-from-issue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ jobs:
if: contains(github.event.issue.labels.*.name, 'add-repo')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
# pin: v6.0.0 -- actions/checkout
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
# pin: v6.0.0 -- actions/setup-node
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903
with:
node-version-file: '.nvmrc'
cache: 'npm'
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/audit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ jobs:
matrix:
path: ['.', 'mcp', 'cli']
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
# pin: v4.2.2 -- actions/checkout
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
# pin: v4.4.0 -- actions/setup-node
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version-file: '.nvmrc'
cache: 'npm'
Expand Down
136 changes: 136 additions & 0 deletions .github/workflows/auto-merge-dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
name: auto-merge-dependabot

# Dependabot opens dependency-bump PRs across four ecosystems (root npm,
# cli npm, mcp npm, github-actions). The vast majority of those bumps are
# semver patch or minor — there is nothing for a human to review beyond
# "do the tests pass?". This workflow auto-approves and enables auto-merge
# for patch+minor; for major bumps it leaves the PR open for a human and
# adds a comment as a poke.
#
# Safety:
# - We use the OFFICIAL `dependabot/fetch-metadata` action which is the
# supported way to retrieve update-type from Dependabot's PR data.
# Trying to scrape the title / body ourselves is brittle and unsafe.
# - Trigger is pull_request_target so the GITHUB_TOKEN can comment +
# enable auto-merge on PRs opened by the Dependabot bot (whose PRs run
# with read-only GITHUB_TOKEN by default). We never check out or
# execute PR-controlled code in this workflow.
# - Author filter is the load-bearing safety check: the job only runs if
# `github.actor == 'dependabot[bot]'`.

on:
pull_request_target:
types: [opened, reopened, synchronize, labeled, ready_for_review]

permissions:
contents: read
pull-requests: write

concurrency:
group: auto-merge-dependabot-${{ github.event.pull_request.number }}
cancel-in-progress: false

jobs:
auto-merge:
name: Auto-merge dependabot patch/minor
runs-on: ubuntu-latest
if: github.actor == 'dependabot[bot]'
timeout-minutes: 20

steps:
- name: Fetch Dependabot metadata
id: meta
# pin: v2.2.0 -- dependabot/fetch-metadata
uses: dependabot/fetch-metadata@dbb049abf0d677abbd7f7eee0375145b417fdd34
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Wait for required checks to succeed
if: >-
steps.meta.outputs.update-type == 'version-update:semver-patch' ||
steps.meta.outputs.update-type == 'version-update:semver-minor'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
UPDATE_TYPE: ${{ steps.meta.outputs.update-type }}
DEPENDENCY_NAMES: ${{ steps.meta.outputs.dependency-names }}
run: |
set -euo pipefail
echo "Dependabot update: type=${UPDATE_TYPE} deps=${DEPENDENCY_NAMES}"
# Same required-check list as auto-merge-release-please.yml. Some
# PRs only touch github-actions metadata and won't trigger smoke
# (smoke is path-filtered). We treat "missing" as skipped so we
# don't block on a check that intentionally didn't run.
required=("validate" "smoke / chromium" "smoke / webkit-iphone" "Analyze (javascript-typescript)")
deadline=$(( $(date +%s) + 15 * 60 ))
while :; do
now=$(date +%s)
if [ "$now" -ge "$deadline" ]; then
echo "::warning::Required checks did not all complete in 15m; will retry on next sync event."
exit 0
fi
all_done=true
any_failed=false
for ctx in "${required[@]}"; do
conclusion=$(gh api "repos/${REPO}/commits/${HEAD_SHA}/check-runs" \
--jq "[.check_runs[] | select(.name==\"${ctx}\")] | (.[-1].conclusion // \"missing\")")
status=$(gh api "repos/${REPO}/commits/${HEAD_SHA}/check-runs" \
--jq "[.check_runs[] | select(.name==\"${ctx}\")] | (.[-1].status // \"missing\")")
echo "check '${ctx}': status=${status} conclusion=${conclusion}"
if [ "$status" = "missing" ]; then
continue
fi
if [ "$status" != "completed" ]; then
all_done=false
elif [ "$conclusion" != "success" ] && [ "$conclusion" != "skipped" ] && [ "$conclusion" != "neutral" ]; then
any_failed=true
fi
done
if $any_failed; then
echo "::warning::At least one required check failed; not enabling auto-merge."
exit 0
fi
if $all_done; then
echo "All required checks completed."
break
fi
sleep 30
done

- name: Approve patch/minor PR
if: >-
steps.meta.outputs.update-type == 'version-update:semver-patch' ||
steps.meta.outputs.update-type == 'version-update:semver-minor'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
UPDATE_TYPE: ${{ steps.meta.outputs.update-type }}
run: |
gh pr review "$PR_NUMBER" --repo "$REPO" --approve \
--body "Auto-approved Dependabot ${UPDATE_TYPE} bump; required checks are green."

- name: Enable auto-merge (squash) for patch/minor
if: >-
steps.meta.outputs.update-type == 'version-update:semver-patch' ||
steps.meta.outputs.update-type == 'version-update:semver-minor'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
gh pr merge "$PR_NUMBER" --repo "$REPO" --auto --squash

- name: Comment on major bumps (human review required)
if: steps.meta.outputs.update-type == 'version-update:semver-major'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
DEPENDENCY_NAMES: ${{ steps.meta.outputs.dependency-names }}
PREVIOUS_VERSION: ${{ steps.meta.outputs.previous-version }}
NEW_VERSION: ${{ steps.meta.outputs.new-version }}
run: |
gh pr comment "$PR_NUMBER" --repo "$REPO" \
--body "Major version bump detected: ${DEPENDENCY_NAMES} ${PREVIOUS_VERSION} -> ${NEW_VERSION}. Auto-merge is disabled for major bumps; please review the changelog and merge manually if safe."
114 changes: 114 additions & 0 deletions .github/workflows/auto-merge-release-please.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: auto-merge-release-please

# release-please opens a per-component Release PR (chore(<component>): release <version>)
# whose contents are purely mechanical: a version bump in package.json /
# pyproject.toml, an updated .release-please-manifest.json, and an appended
# CHANGELOG.md entry. There is nothing here for a human to review beyond
# "did the bot do what the bot is supposed to do?"
#
# This workflow waits for the required status checks to land green on the
# PR head, auto-approves with the GH bot, and enables auto-merge in squash
# mode. Merging the squashed commit creates the component tag
# (e.g. `cli-v0.1.3`) which fires the existing `publish-*.yml` workflows.
#
# Safety:
# - Trigger is pull_request_target (needed so the GITHUB_TOKEN has write
# scope on PRs from forks), but we ONLY auto-approve PRs authored by
# release-please[bot] AND we never check out or execute PR-controlled
# code in this workflow. The only operations are GitHub API calls.
# - All untrusted event values (PR number, head SHA, login) are read via
# env: bindings and only referenced as quoted shell vars — never
# interpolated into a run: body directly.
# - The required status checks list matches the repo's branch-protection
# contexts (validate, smoke/chromium, smoke/webkit-iphone, codeql); we
# re-check them explicitly here as defense-in-depth in case branch
# protection is loosened in the future.

on:
pull_request_target:
types: [opened, reopened, synchronize, labeled, ready_for_review]

permissions:
contents: read
pull-requests: write

concurrency:
group: auto-merge-release-please-${{ github.event.pull_request.number }}
cancel-in-progress: false

jobs:
auto-merge:
name: Auto-merge release-please PR
runs-on: ubuntu-latest
# Author filter is the load-bearing safety check. release-please runs as
# `release-please[bot]` on the GitHub App, or as `github-actions[bot]`
# when triggered via workflow_dispatch through the action. We accept
# both, but we ALSO never check out PR contents in this workflow.
if: >-
github.event.pull_request.user.login == 'release-please[bot]' ||
github.event.pull_request.user.login == 'github-actions[bot]'
timeout-minutes: 20

steps:
- name: Wait for required checks to succeed
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
set -euo pipefail
# The four required checks (validate is a check-run, smoke has
# two matrix jobs, codeql is the security analysis). If any of
# these is still pending after the timeout we exit non-zero so
# the workflow re-runs on the next sync event.
required=("validate" "smoke / chromium" "smoke / webkit-iphone" "Analyze (javascript-typescript)")
deadline=$(( $(date +%s) + 15 * 60 ))
Comment on lines +61 to +66
while :; do
now=$(date +%s)
if [ "$now" -ge "$deadline" ]; then
echo "::warning::Required checks did not all complete in 15m; will retry on next sync event."
exit 0
fi
all_done=true
any_failed=false
for ctx in "${required[@]}"; do
# The latest run of each named check on the head sha.
conclusion=$(gh api "repos/${REPO}/commits/${HEAD_SHA}/check-runs" \
--jq "[.check_runs[] | select(.name==\"${ctx}\")] | (.[-1].conclusion // \"missing\")")
status=$(gh api "repos/${REPO}/commits/${HEAD_SHA}/check-runs" \
--jq "[.check_runs[] | select(.name==\"${ctx}\")] | (.[-1].status // \"missing\")")
echo "check '${ctx}': status=${status} conclusion=${conclusion}"
if [ "$status" != "completed" ]; then
all_done=false
elif [ "$conclusion" != "success" ] && [ "$conclusion" != "skipped" ] && [ "$conclusion" != "neutral" ]; then
any_failed=true
fi
done
if $any_failed; then
echo "::warning::At least one required check failed; not enabling auto-merge."
exit 0
fi
if $all_done; then
echo "All required checks completed successfully."
break
fi
sleep 30
done

- name: Approve PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
gh pr review "$PR_NUMBER" --repo "$REPO" --approve \
--body "Auto-approved release-please PR. Mechanical version bump + changelog only; required checks are green."

- name: Enable auto-merge (squash)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
gh pr merge "$PR_NUMBER" --repo "$REPO" --auto --squash
3 changes: 2 additions & 1 deletion .github/workflows/auto-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ jobs:
auto-merge:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
# pin: v6.0.0 -- actions/checkout
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
with:
fetch-depth: 0

Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ jobs:
language: ["javascript-typescript"]

steps:
# pin: v6.0.0 -- actions/checkout
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3

# pin: v4.35.4 -- github/codeql-action
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e
with:
languages: ${{ matrix.language }}
queries: security-and-quality
Expand All @@ -58,7 +60,8 @@ jobs:
- "**/node_modules/**"
- "**/dist/**"

# pin: v4.35.4 -- github/codeql-action
- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@68bde559dea0fdcac2102bfdf6230c5f70eb485e
with:
category: "/language:${{ matrix.language }}"
6 changes: 4 additions & 2 deletions .github/workflows/docs-on-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ jobs:
update-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
# pin: v6.0.0 -- actions/checkout
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 1
- uses: actions/setup-node@v6
# pin: v6.0.0 -- actions/setup-node
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903
with:
node-version-file: '.nvmrc'

Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/node-matrix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ jobs:
matrix:
node-version: [18.x, 20.x, 22.x]
steps:
- uses: actions/checkout@v6
# pin: v6.0.0 -- actions/checkout
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3
# pin: v6.0.0 -- actions/setup-node
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903
with:
node-version: ${{ matrix.node-version }}
cache: "npm"
Expand Down
Loading
Loading