From c242ec18dcda6c0a9994b7eb2088a3b52e365c35 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 9 Apr 2026 09:12:24 +0100 Subject: [PATCH 1/6] update dependabot job Signed-off-by: Simon Davies --- .github/dependabot.yml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index bc11829..955879a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,23 +1,26 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file - version: 2 -updates: +updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "daily" time: "03:00" + open-pull-requests-limit: 20 + - package-ecosystem: "cargo" - directories: - - "/" + directories: + - "/src/sandbox/runtime" + - "/src/code-validator/guest" schedule: interval: "daily" time: "03:00" + open-pull-requests-limit: 20 + - package-ecosystem: "npm" - directory: "/src/js-host-api" + directories: + - "/" + - "/src/code-validator/guest" schedule: interval: "daily" time: "03:00" + open-pull-requests-limit: 20 From 1da23d1ca42f43ee3f222b698c8762c540d1a91d Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 9 Apr 2026 09:21:46 +0100 Subject: [PATCH 2/6] auto apporve dependabot PRs Signed-off-by: Simon Davies --- .github/workflows/auto-merge-dependabot.yml | 52 +++++++ scripts/auto-approve-dependabot.sh | 145 ++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 .github/workflows/auto-merge-dependabot.yml create mode 100644 scripts/auto-approve-dependabot.sh diff --git a/.github/workflows/auto-merge-dependabot.yml b/.github/workflows/auto-merge-dependabot.yml new file mode 100644 index 0000000..d176c2a --- /dev/null +++ b/.github/workflows/auto-merge-dependabot.yml @@ -0,0 +1,52 @@ +name: Auto Merge Dependabot PRs + +on: + schedule: + # Run daily at 04:00 UTC since dependabot runs at 03:00 UTC + - cron: '0 4 * * *' + workflow_dispatch: # Allow manual trigger + +# This workflow uses a GitHub App token to approve and merge Dependabot PRs +# The token is created using the `actions/create-github-app-token` action +# The token is used so that the updates are made by the GitHub App instead of Github Actions +# and will show up as such in the PR comments and history +# In addition, the token is scoped to only the permissions needed for this workflow +# see https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/making-authenticated-api-requests-with-a-github-app-in-a-github-actions-workflow for details + +jobs: + auto-merge-dependabot: + permissions: + contents: read + runs-on: ubuntu-latest + steps: + + # Gets the GitHub App token + - uses: actions/create-github-app-token@v3 + id: get-app-token + with: + # required + app-id: ${{ secrets.DEPENDABOT_APP_ID }} + private-key: ${{ secrets.DEPENDABOT_APP_KEY }} + permission-pull-requests: write + permission-contents: write + permission-checks: read + permission-actions: read + + - name: Checkout code + uses: actions/checkout@v6 + with: + token: ${{ steps.get-app-token.outputs.token }} + persist-credentials: false + + - name: Setup GitHub CLI + run: | + # GitHub CLI is pre-installed on GitHub-hosted runners + gh --version + + - name: Make script executable + run: chmod +x ./scripts/auto-approve-dependabot.sh + + - name: Run auto approve script + env: + GITHUB_TOKEN: ${{ steps.get-app-token.outputs.token }} + run: ./scripts/auto-approve-dependabot.sh ${{ github.repository }} diff --git a/scripts/auto-approve-dependabot.sh b/scripts/auto-approve-dependabot.sh new file mode 100644 index 0000000..afa4041 --- /dev/null +++ b/scripts/auto-approve-dependabot.sh @@ -0,0 +1,145 @@ +#!/bin/bash +set -e +set -o pipefail + +# This script checks for open PRs from dependabot that have all checks passing and have not been +# modified by another user, and approves+merges them automatically. +# To be run as a GitHub action. + +# Check if repository argument is provided +if [ -z "$1" ]; then + echo "Error: Repository name not provided." + echo "Usage: $0 " + echo "Example: $0 hyperlight-dev/hyperlight" + exit 1 +fi + +REPO="$1" +echo "Checking for open Dependabot PRs to approve and merge in $REPO..." + +# Get all open PRs from dependabot +# We filter so that only PRs that are not from forks and are in branches starting with "dependabot/cargo" are included. +dependabot_prs=$(gh pr list -R "$REPO" --author "dependabot[bot]" --state open --json number,title,reviews,headRepositoryOwner,headRefName | jq --arg repo_owner "$(echo "$REPO" | cut -d'/' -f1)" '[.[] | select(.headRepositoryOwner.login == $repo_owner and (.headRefName | startswith("dependabot/cargo")))]') +# Exit early if no PRs found +if [ -z "$dependabot_prs" ] || [ "$dependabot_prs" = "[]" ]; then + echo "No open Dependabot PRs found in $REPO" + exit 0 +fi + +# Count how many PRs we found +pr_count=$(echo "$dependabot_prs" | jq 'length') +echo "Found $pr_count open Dependabot PRs in $REPO" + +# Process each PR +echo "$dependabot_prs" | jq -c '.[]' | while read -r pr; do + pr_number=$(echo "$pr" | jq -r '.number') + pr_title=$(echo "$pr" | jq -r '.title') + + echo "Processing PR #$pr_number: $pr_title" + + # Check if PR only modifies allowed files + pr_files=$(gh pr view "$pr_number" -R "$REPO" --json files) + invalid_files=$(echo "$pr_files" | jq -r '.files[].path' | grep -v -E '(Cargo\.toml|Cargo\.lock)' || true) + + if [ -n "$invalid_files" ]; then + echo " ❌ PR #$pr_number modifies files that are not allowed for auto-merge:" + echo ${invalid_files/#/ - } + echo " â„šī¸ Only changes to Cargo.toml and Cargo.lock are allowed" + continue + fi + + echo " ✅ PR #$pr_number only modifies allowed files (Cargo.toml and Cargo.lock)" + + # First, get detailed PR information including all checks + pr_details=$(gh pr view "$pr_number" -R "$REPO" --json statusCheckRollup,state) + + # Check if all status checks have passed (regardless of required or not) + all_checks_pass=true + has_pending_checks=false + failed_checks="" + + # First identify checks that are still in progress + pending_checks=$(echo "$pr_details" | jq -r '.statusCheckRollup[] | select(.status == "IN_PROGRESS" or .status == "QUEUED" or .status == "PENDING") | .name') + + # Check for permission-required checks + permission_required_checks=$(echo "$pr_details" | jq -r '.statusCheckRollup[] | select(.status == "WAITING" or .status == "ACTION_REQUIRED" or (.status == "QUEUED" and .conclusion == null and .detailsUrl != null and (.detailsUrl | contains("waiting-for-approval")))) | .name') + + # Dont approve if there are checks required that need permission to run + if [ -n "$permission_required_checks" ]; then + echo " 🔐 PR #$pr_number has checks waiting for permission:" + echo "$permission_required_checks" | sed 's/^/ - /' + echo " ❌ Skipping auto-approval due to permission-required checks" + continue + fi + + if [ -n "$pending_checks" ]; then + echo " âŗ PR #$pr_number has pending checks:" + echo "$pending_checks" | sed 's/^/ - /' + echo " â„šī¸ We will still approve the PR so it can merge automatically once all checks pass" + has_pending_checks=true + fi + + # Check for failed checks - only include checks that have a conclusion and are not still running + # Explicitly exclude checks with status IN_PROGRESS, QUEUED, or PENDING + failed_checks=$(echo "$pr_details" | jq -r '.statusCheckRollup[] | + select(.conclusion != null and + .conclusion != "SUCCESS" and + .conclusion != "NEUTRAL" and + .conclusion != "SKIPPED" and + .status != "IN_PROGRESS" and + .status != "QUEUED" and + .status != "PENDING") | .name') + + if [ -n "$failed_checks" ]; then + echo " ❌ PR #$pr_number has failed checks:" + echo "$failed_checks" | sed 's/^/ - /' + all_checks_pass=false + continue + fi + + # If we've reached here, either all checks have passed or some are pending + if [ "$has_pending_checks" = false ]; then + echo " ✅ All status checks passed for PR #$pr_number" + fi + + # Check if PR has been modified by someone other than dependabot + pr_commits=$(gh pr view "$pr_number" -R "$REPO" --json commits) + non_dependabot_authors=$(echo "$pr_commits" | jq -r '.commits[].authors[].login' | grep -v -e "dependabot\[bot\]" -e "^$" || true) + + if [ -n "$non_dependabot_authors" ]; then + echo " ❌ PR #$pr_number has been modified by users other than dependabot: $non_dependabot_authors" + continue + fi + + # Check if PR needs approval (i.e., hasn't been approved already) + already_approved=$(echo "$pr" | jq -r '.reviews[] | select(.state == "APPROVED") | .state' | grep -c "APPROVED" || true) + + if [ "$already_approved" -eq 0 ]; then + echo " ✅ Approving PR #$pr_number" + gh pr review "$pr_number" -R "$REPO" --approve -b "Automatically approved by dependabot auto-approve workflow" + else + echo " â„šī¸ PR #$pr_number is already approved" + fi + + if [ "$has_pending_checks" = true ] || [ "$all_checks_pass" = true ]; then + # Check if PR is up-to-date with base branch + merge_status=$(gh pr view "$pr_number" -R "$REPO" --json mergeStateStatus -q '.mergeStateStatus') + + if [ "$merge_status" != "CLEAN" ]; then + echo " âš ī¸ PR #$pr_number is not up to date (status: $merge_status)" + # Enable auto-merge to merge once checks pass + echo " ✅ Enabling auto-merge (squash strategy) for PR #$pr_number" + gh pr merge "$pr_number" -R "$REPO" --auto --squash + echo " ✅ Auto-merge enabled for PR #$pr_number" + else + echo " ✅ PR #$pr_number is up to date with base branch" + # PR is already clean/mergeable - merge directly instead of enabling auto-merge + echo " ✅ Merging PR #$pr_number directly (squash strategy)" + gh pr merge "$pr_number" -R "$REPO" --squash + echo " ✅ PR #$pr_number merged successfully" + fi + fi + +done + +echo "Finished processing Dependabot PRs for $REPO" From 046bdbb34e16e638004b22cbde467e13fbe41621 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 9 Apr 2026 10:03:50 +0100 Subject: [PATCH 3/6] fix 1ES runners Signed-off-by: Simon Davies --- .github/workflows/pr-validate.yml | 17 +++++++++-------- .github/workflows/publish.yml | 14 +++++++++----- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/.github/workflows/pr-validate.yml b/.github/workflows/pr-validate.yml index 59ffb98..d323b3c 100644 --- a/.github/workflows/pr-validate.yml +++ b/.github/workflows/pr-validate.yml @@ -59,7 +59,7 @@ jobs: name: Lint & Test needs: [docs-pr] if: needs.docs-pr.outputs.docs-only != 'true' - runs-on: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"] + runs-on: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd","JobId=hyperagent-pr-validate-${{ github.run_id }}-${{ github.run_number }}-${{ github.run_attempt }}"] steps: - uses: actions/checkout@v6 @@ -99,30 +99,31 @@ jobs: - windows-whp-release include: - build: linux-kvm-debug - os: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"] hypervisor: kvm config: debug - build: linux-kvm-release - os: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"] hypervisor: kvm config: release - build: linux-mshv-debug - os: [self-hosted, Linux, X64, "1ES.Pool=hld-azlinux3-mshv-amd"] hypervisor: mshv config: debug - build: linux-mshv-release - os: [self-hosted, Linux, X64, "1ES.Pool=hld-azlinux3-mshv-amd"] hypervisor: mshv config: release - build: windows-whp-debug - os: [self-hosted, Windows, X64, "1ES.Pool=hld-win2022-amd"] hypervisor: whp config: debug - build: windows-whp-release - os: [self-hosted, Windows, X64, "1ES.Pool=hld-win2022-amd"] hypervisor: whp config: release - runs-on: ${{ matrix.os }} + runs-on: ${{ fromJson( + format('["self-hosted", "{0}", "X64", "1ES.Pool=hld-{1}-amd", "JobId={2}-{3}-{4}-{5}"]', + matrix.hypervisor == 'whp' && 'Windows' || 'Linux', + matrix.hypervisor == 'whp' && 'win2022' || matrix.hypervisor == 'mshv' && 'azlinux3-mshv' || 'kvm', + matrix.build, + github.run_id, + github.run_number, + github.run_attempt)) }} steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8a27bb8..b3dde36 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -34,18 +34,22 @@ jobs: build: [linux-kvm, linux-musl, windows-whp] include: - build: linux-kvm - os: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"] hypervisor: kvm run_tests: true - build: linux-musl - os: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"] hypervisor: kvm run_tests: false # musl .node can't run on glibc host - build: windows-whp - os: [self-hosted, Windows, X64, "1ES.Pool=hld-win2022-amd"] hypervisor: whp run_tests: true - runs-on: ${{ matrix.os }} + runs-on: ${{ fromJson( + format('["self-hosted", "{0}", "X64", "1ES.Pool=hld-{1}-amd", "JobId={2}-{3}-{4}-{5}"]', + matrix.hypervisor == 'whp' && 'Windows' || 'Linux', + matrix.hypervisor == 'whp' && 'win2022' || 'kvm', + matrix.build, + github.run_id, + github.run_number, + github.run_attempt)) }} steps: - uses: actions/checkout@v6 @@ -110,7 +114,7 @@ jobs: publish-npm: name: Publish to npmjs.org needs: [build-native] - runs-on: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"] + runs-on: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd","JobId=hyperagent-publish-npm-${{ github.run_id }}-${{ github.run_number }}-${{ github.run_attempt }}"] steps: - uses: actions/checkout@v6 From ec7ec722686876628a759303759b5d7cae8a9e56 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 9 Apr 2026 10:52:28 +0100 Subject: [PATCH 4/6] move to windows 2025 Signed-off-by: Simon Davies --- .github/workflows/pr-validate.yml | 2 +- .github/workflows/publish.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-validate.yml b/.github/workflows/pr-validate.yml index d323b3c..e05a615 100644 --- a/.github/workflows/pr-validate.yml +++ b/.github/workflows/pr-validate.yml @@ -119,7 +119,7 @@ jobs: runs-on: ${{ fromJson( format('["self-hosted", "{0}", "X64", "1ES.Pool=hld-{1}-amd", "JobId={2}-{3}-{4}-{5}"]', matrix.hypervisor == 'whp' && 'Windows' || 'Linux', - matrix.hypervisor == 'whp' && 'win2022' || matrix.hypervisor == 'mshv' && 'azlinux3-mshv' || 'kvm', + matrix.hypervisor == 'whp' && 'win2025' || matrix.hypervisor == 'mshv' && 'azlinux3-mshv' || 'kvm', matrix.build, github.run_id, github.run_number, diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b3dde36..08f100d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -45,7 +45,7 @@ jobs: runs-on: ${{ fromJson( format('["self-hosted", "{0}", "X64", "1ES.Pool=hld-{1}-amd", "JobId={2}-{3}-{4}-{5}"]', matrix.hypervisor == 'whp' && 'Windows' || 'Linux', - matrix.hypervisor == 'whp' && 'win2022' || 'kvm', + matrix.hypervisor == 'whp' && 'win2025' || 'kvm', matrix.build, github.run_id, github.run_number, From 65b4e3815e9ed24979019f0c8ae0d69e772f034c Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 9 Apr 2026 11:31:36 +0100 Subject: [PATCH 5/6] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/auto-merge-dependabot.yml | 2 +- scripts/auto-approve-dependabot.sh | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/auto-merge-dependabot.yml b/.github/workflows/auto-merge-dependabot.yml index d176c2a..c9ce728 100644 --- a/.github/workflows/auto-merge-dependabot.yml +++ b/.github/workflows/auto-merge-dependabot.yml @@ -8,7 +8,7 @@ on: # This workflow uses a GitHub App token to approve and merge Dependabot PRs # The token is created using the `actions/create-github-app-token` action -# The token is used so that the updates are made by the GitHub App instead of Github Actions +# The token is used so that the updates are made by the GitHub App instead of GitHub Actions # and will show up as such in the PR comments and history # In addition, the token is scoped to only the permissions needed for this workflow # see https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/making-authenticated-api-requests-with-a-github-app-in-a-github-actions-workflow for details diff --git a/scripts/auto-approve-dependabot.sh b/scripts/auto-approve-dependabot.sh index afa4041..a26c781 100644 --- a/scripts/auto-approve-dependabot.sh +++ b/scripts/auto-approve-dependabot.sh @@ -43,7 +43,7 @@ echo "$dependabot_prs" | jq -c '.[]' | while read -r pr; do if [ -n "$invalid_files" ]; then echo " ❌ PR #$pr_number modifies files that are not allowed for auto-merge:" - echo ${invalid_files/#/ - } + printf '%s\n' "$invalid_files" | sed 's/^/ - /' echo " â„šī¸ Only changes to Cargo.toml and Cargo.lock are allowed" continue fi @@ -64,7 +64,7 @@ echo "$dependabot_prs" | jq -c '.[]' | while read -r pr; do # Check for permission-required checks permission_required_checks=$(echo "$pr_details" | jq -r '.statusCheckRollup[] | select(.status == "WAITING" or .status == "ACTION_REQUIRED" or (.status == "QUEUED" and .conclusion == null and .detailsUrl != null and (.detailsUrl | contains("waiting-for-approval")))) | .name') - # Dont approve if there are checks required that need permission to run + # Don't approve if there are checks required that need permission to run if [ -n "$permission_required_checks" ]; then echo " 🔐 PR #$pr_number has checks waiting for permission:" echo "$permission_required_checks" | sed 's/^/ - /' @@ -121,19 +121,24 @@ echo "$dependabot_prs" | jq -c '.[]' | while read -r pr; do echo " â„šī¸ PR #$pr_number is already approved" fi - if [ "$has_pending_checks" = true ] || [ "$all_checks_pass" = true ]; then + if [ "$has_pending_checks" = true ]; then + echo " âŗ PR #$pr_number still has pending checks" + echo " ✅ Enabling auto-merge (squash strategy) for PR #$pr_number" + gh pr merge "$pr_number" -R "$REPO" --auto --squash + echo " ✅ Auto-merge enabled for PR #$pr_number" + elif [ "$all_checks_pass" = true ]; then # Check if PR is up-to-date with base branch merge_status=$(gh pr view "$pr_number" -R "$REPO" --json mergeStateStatus -q '.mergeStateStatus') if [ "$merge_status" != "CLEAN" ]; then echo " âš ī¸ PR #$pr_number is not up to date (status: $merge_status)" - # Enable auto-merge to merge once checks pass + # Enable auto-merge to merge once branch is up to date echo " ✅ Enabling auto-merge (squash strategy) for PR #$pr_number" gh pr merge "$pr_number" -R "$REPO" --auto --squash echo " ✅ Auto-merge enabled for PR #$pr_number" else echo " ✅ PR #$pr_number is up to date with base branch" - # PR is already clean/mergeable - merge directly instead of enabling auto-merge + # PR is already clean/mergeable and checks have passed - merge directly echo " ✅ Merging PR #$pr_number directly (squash strategy)" gh pr merge "$pr_number" -R "$REPO" --squash echo " ✅ PR #$pr_number merged successfully" From 82c900489589889e3e2c85442d61aa6a9167f039 Mon Sep 17 00:00:00 2001 From: Simon Davies Date: Thu, 9 Apr 2026 11:31:57 +0100 Subject: [PATCH 6/6] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/auto-approve-dependabot.sh | 35 +++++++++++++++++++----------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/scripts/auto-approve-dependabot.sh b/scripts/auto-approve-dependabot.sh index a26c781..fbd1927 100644 --- a/scripts/auto-approve-dependabot.sh +++ b/scripts/auto-approve-dependabot.sh @@ -130,19 +130,28 @@ echo "$dependabot_prs" | jq -c '.[]' | while read -r pr; do # Check if PR is up-to-date with base branch merge_status=$(gh pr view "$pr_number" -R "$REPO" --json mergeStateStatus -q '.mergeStateStatus') - if [ "$merge_status" != "CLEAN" ]; then - echo " âš ī¸ PR #$pr_number is not up to date (status: $merge_status)" - # Enable auto-merge to merge once branch is up to date - echo " ✅ Enabling auto-merge (squash strategy) for PR #$pr_number" - gh pr merge "$pr_number" -R "$REPO" --auto --squash - echo " ✅ Auto-merge enabled for PR #$pr_number" - else - echo " ✅ PR #$pr_number is up to date with base branch" - # PR is already clean/mergeable and checks have passed - merge directly - echo " ✅ Merging PR #$pr_number directly (squash strategy)" - gh pr merge "$pr_number" -R "$REPO" --squash - echo " ✅ PR #$pr_number merged successfully" - fi + case "$merge_status" in + CLEAN) + echo " ✅ PR #$pr_number is up to date with base branch" + # PR is already clean/mergeable - merge directly instead of enabling auto-merge + echo " ✅ Merging PR #$pr_number directly (squash strategy)" + gh pr merge "$pr_number" -R "$REPO" --squash + echo " ✅ PR #$pr_number merged successfully" + ;; + BEHIND) + echo " âš ī¸ PR #$pr_number is behind the base branch" + # Enable auto-merge to merge once the branch is updated and checks pass + echo " ✅ Enabling auto-merge (squash strategy) for PR #$pr_number" + gh pr merge "$pr_number" -R "$REPO" --auto --squash + echo " ✅ Auto-merge enabled for PR #$pr_number" + ;; + DIRTY|BLOCKED) + echo " âš ī¸ Skipping PR #$pr_number because it cannot be auto-merged (status: $merge_status)" + ;; + *) + echo " âš ī¸ Skipping PR #$pr_number due to unsupported merge status: $merge_status" + ;; + esac fi done