Add workflow to prevent quick changes to website dependencies, update website handbook page (#44765)
Changes: - Added a new Github workflow that runs on branches that change the website's dependencies (website/package-lock.json or website/package.json), and fails for 72 hours after a change to those files have been made. After 72 hours, if the workflow has not run again on a pull request, the workflow can be rerun to give a PR a passing status. - Updated the website handbook page to document this process. @lukeheath After this is merged, I will need help setting up a branch protection rule to require a passing status from this workflow to merge pull requests that change the website's dependencies <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Added an automated workflow to enforce a wait period before website dependency updates can proceed, preventing premature merges. * Added scheduled and manual re-triggering for recent failed workflow runs to ensure dependency checks are retried without manual intervention. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
name: Incubate website dependency changes
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'website/package.json'
|
||||
- 'website/package-lock.json'
|
||||
schedule:
|
||||
- cron: '0 7 * * *' # 7am UTC nightly
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write # needed for `gh run rerun`
|
||||
|
||||
concurrency:
|
||||
group: incubate-website-deps-${{ github.event.pull_request.number || github.run_id }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
INCUBATION_HOURS: 72
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
with:
|
||||
fetch-depth: 0 # full history needed to compute commit timestamp
|
||||
|
||||
- name: Verify 72-hour incubation
|
||||
if: github.event_name == 'pull_request'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
git fetch --no-tags origin "${GITHUB_BASE_REF}"
|
||||
THRESHOLD_SECONDS=$(( INCUBATION_HOURS * 3600 ))
|
||||
# Confirm this PR branch actually touches the dep files.
|
||||
HAS_DEP_CHANGE=$(git log -1 --format=%H \
|
||||
"origin/${GITHUB_BASE_REF}..HEAD" \
|
||||
-- website/package.json website/package-lock.json || true)
|
||||
if [ -z "${HAS_DEP_CHANGE}" ]; then
|
||||
echo "No website dependency changes on this branch relative to ${GITHUB_BASE_REF}."
|
||||
exit 0
|
||||
fi
|
||||
# Use the wall-clock creation time of the *earliest* run for this workflow
|
||||
# on this PR — unaffected by force-pushed commit timestamps.
|
||||
EARLIEST_RUN_TS=$(gh run list \
|
||||
--repo "${GITHUB_REPOSITORY}" \
|
||||
--workflow "${{ github.workflow }}" \
|
||||
--event pull_request \
|
||||
--branch "${{ github.head_ref }}" \
|
||||
--limit 100 \
|
||||
--json databaseId,createdAt \
|
||||
--jq 'sort_by(.createdAt) | .[0].createdAt' )
|
||||
EARLIEST_RUN_EPOCH=$(date -d "${EARLIEST_RUN_TS}" +%s)
|
||||
AGE=$(( $(date +%s) - EARLIEST_RUN_EPOCH ))
|
||||
AGE_HOURS=$(( AGE / 3600 ))
|
||||
if [ "${AGE}" -lt "${THRESHOLD_SECONDS}" ]; then
|
||||
REMAINING=$(( (THRESHOLD_SECONDS - AGE + 3599) / 3600 ))
|
||||
echo "::error::Website dependency files were changed ${AGE_HOURS}h ago. Incubation period is ${INCUBATION_HOURS}h. Wait ~${REMAINING}h, then re-run this check."
|
||||
exit 1
|
||||
fi
|
||||
echo "Incubation complete: last website dep change was ${AGE_HOURS}h ago."
|
||||
|
||||
- name: Re-run previously-failed PR checks (nightly)
|
||||
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Find recent failed runs of THIS workflow on pull_request events and re-trigger them.
|
||||
# As wall-clock time advances, the git-log age in each rerun grows past the 72h threshold
|
||||
# and the run passes — flipping the required check green without requiring a force-push.
|
||||
gh run list \
|
||||
--repo "${GITHUB_REPOSITORY}" \
|
||||
--workflow "${{ github.workflow }}" \
|
||||
--event pull_request \
|
||||
--status failure \
|
||||
--created ">$(date -u -d '7 days ago' '+%Y-%m-%dT%H:%M:%SZ')" \
|
||||
--limit 100 \
|
||||
--json databaseId \
|
||||
--jq '.[].databaseId' \
|
||||
| while read -r run_id; do
|
||||
echo "Re-running failed run ${run_id}"
|
||||
gh run rerun "${run_id}" --repo "${GITHUB_REPOSITORY}" || true
|
||||
done
|
||||
@@ -134,6 +134,11 @@ Every week, the website maintainer looks for any new [code scanning alerts](http
|
||||
- If the alert is for a dependency that runs in production, the maintainer will upgrade it to a version that is not affected by the vulnerability.
|
||||
- If the alert is for a devDependency or a dependency of a devDependency, the maintainer will dismiss the alert as a false-positive, because it does not affect the production environment.
|
||||
|
||||
## Incubate website dependency changes
|
||||
|
||||
Pull requests that modify `website/package.json` or `website/package-lock.json` must wait 72 hours after the most recent commit to either file before they can merge to `main`. This incubation period gives the maintainer time to spot regressions or supply-chain concerns introduced by a dependency bump before it reaches the website's production environment.
|
||||
|
||||
The `Incubate website dependency changes` GitHub Actions workflow enforces this as a required status check. The check runs on every PR that touches those files and re-evaluates open PRs nightly, once 72 hours have elapsed the check turns green automatically. Pushing a new commit to either file resets the clock.
|
||||
|
||||
|
||||
<meta name="maintainedBy" value="lukeheath">
|
||||
|
||||
Reference in New Issue
Block a user