Skip to content

Commit 61a782a

Browse files
committed
Make sure dependabot PRs update guests cargo.lock
Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
1 parent 8010a70 commit 61a782a

File tree

1 file changed

+175
-0
lines changed

1 file changed

+175
-0
lines changed
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# This workflow automatically updates the Cargo.lock files in guest crates when
2+
# Dependabot updates dependencies. Without this, Dependabot PRs only update the
3+
# root Cargo.lock, leaving the guest crate Cargo.lock files stale.
4+
#
5+
# See: https://docs.github.com/en/code-security/tutorials/secure-your-dependencies/automating-dependabot-with-github-actions
6+
7+
name: Update Guest Cargo.lock for Dependabot PRs
8+
9+
on:
10+
pull_request:
11+
branches: [main]
12+
paths:
13+
- 'Cargo.toml'
14+
- 'Cargo.lock'
15+
- 'src/hyperlight_*/Cargo.toml'
16+
17+
permissions:
18+
contents: read # Required for actions/checkout to clone the repo
19+
pull-requests: read # Required for dependabot/fetch-metadata to read PR info
20+
21+
env:
22+
CARGO_TERM_COLOR: always
23+
24+
jobs:
25+
update-guest-locks:
26+
# Only run for Dependabot PRs - check the PR author, not the actor
27+
if: github.event.pull_request.user.login == 'dependabot[bot]'
28+
runs-on: [self-hosted, Linux, X64, "1ES.Pool=hld-kvm-amd"]
29+
timeout-minutes: 15
30+
steps:
31+
# Fetch metadata about the Dependabot PR
32+
- name: Dependabot metadata
33+
id: metadata
34+
uses: dependabot/fetch-metadata@v2
35+
with:
36+
github-token: "${{ secrets.GITHUB_TOKEN }}"
37+
38+
# Only proceed for cargo ecosystem updates
39+
- name: Check if cargo update
40+
id: check-ecosystem
41+
run: |
42+
if [ "${{ steps.metadata.outputs.package-ecosystem }}" = "cargo" ]; then
43+
echo "is_cargo=true" >> "$GITHUB_OUTPUT"
44+
else
45+
echo "is_cargo=false" >> "$GITHUB_OUTPUT"
46+
echo "Skipping non-cargo dependency update"
47+
fi
48+
49+
# Get GitHub App token for pushing commits back to the PR
50+
# Uses the same app as auto-merge-dependabot.yml
51+
- name: Get GitHub App token
52+
if: steps.check-ecosystem.outputs.is_cargo == 'true'
53+
uses: actions/create-github-app-token@v2
54+
id: get-app-token
55+
with:
56+
app-id: ${{ secrets.DEPENDABOT_APP_ID }}
57+
private-key: ${{ secrets.DEPENDABOT_APP_KEY }}
58+
permission-contents: write
59+
60+
- name: Checkout PR branch
61+
if: steps.check-ecosystem.outputs.is_cargo == 'true'
62+
uses: actions/checkout@v6
63+
with:
64+
token: ${{ steps.get-app-token.outputs.token }}
65+
ref: ${{ github.head_ref }}
66+
fetch-depth: 0
67+
persist-credentials: false
68+
69+
- name: Setup Rust toolchain
70+
if: steps.check-ecosystem.outputs.is_cargo == 'true'
71+
uses: hyperlight-dev/ci-setup-workflow@v1.8.0
72+
with:
73+
rust-toolchain: "1.89"
74+
env:
75+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
76+
77+
- name: Fix cargo home permissions
78+
if: steps.check-ecosystem.outputs.is_cargo == 'true'
79+
run: |
80+
sudo chown -R $(id -u):$(id -g) /opt/cargo || true
81+
82+
- name: Update simpleguest Cargo.lock
83+
if: steps.check-ecosystem.outputs.is_cargo == 'true'
84+
working-directory: src/tests/rust_guests/simpleguest
85+
run: cargo fetch
86+
87+
- name: Update dummyguest Cargo.lock
88+
if: steps.check-ecosystem.outputs.is_cargo == 'true'
89+
working-directory: src/tests/rust_guests/dummyguest
90+
run: cargo fetch
91+
92+
- name: Update witguest Cargo.lock
93+
if: steps.check-ecosystem.outputs.is_cargo == 'true'
94+
working-directory: src/tests/rust_guests/witguest
95+
run: cargo fetch
96+
97+
# Commits created via the Git Data API are automatically signed/verified
98+
# by GitHub when authenticated as a GitHub App and no custom author or
99+
# committer info is provided.
100+
#
101+
# References:
102+
# - Signature verification for bots:
103+
# https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification#signature-verification-for-bots
104+
# - How to Use Commit Signing with GitHub Apps:
105+
# https://github.com/orgs/community/discussions/50055
106+
# - Git Data API (Create a commit):
107+
# https://docs.github.com/en/rest/git/commits#create-a-commit
108+
- name: Commit and push changes via API
109+
if: steps.check-ecosystem.outputs.is_cargo == 'true'
110+
env:
111+
GH_TOKEN: ${{ steps.get-app-token.outputs.token }}
112+
DEPENDENCY_NAMES: ${{ steps.metadata.outputs.dependency-names }}
113+
BRANCH: ${{ github.head_ref }}
114+
REPO: ${{ github.repository }}
115+
run: |
116+
set -euo pipefail
117+
118+
# Check if there are any changes to the guest Cargo.lock files
119+
if git diff --quiet -- src/tests/rust_guests/*/Cargo.lock; then
120+
echo "No changes to guest Cargo.lock files"
121+
exit 0
122+
fi
123+
124+
echo "Guest Cargo.lock files have changed, committing via API..."
125+
126+
# Get app identity for DCO sign-off trailer
127+
app_slug=$(gh api /app --jq .slug)
128+
app_user_id=$(gh api "/users/${app_slug}[bot]" --jq .id)
129+
130+
# Get current branch HEAD and its tree
131+
HEAD_SHA=$(gh api "/repos/${REPO}/git/ref/heads/${BRANCH}" --jq .object.sha)
132+
BASE_TREE=$(gh api "/repos/${REPO}/git/commits/${HEAD_SHA}" --jq .tree.sha)
133+
134+
# Build tree entries with file content for each changed Cargo.lock.
135+
# The tree API accepts "content" directly and creates blobs for us,
136+
# avoiding the need for separate blob creation API calls.
137+
TREE_JSON="[]"
138+
for file in $(git diff --name-only -- src/tests/rust_guests/*/Cargo.lock); do
139+
TREE_JSON=$(jq \
140+
--arg path "$file" \
141+
--arg content "$(cat "$file")" \
142+
'. + [{"path": $path, "mode": "100644", "type": "blob", "content": $content}]' \
143+
<<< "$TREE_JSON")
144+
done
145+
146+
# Create a new tree with the updated files
147+
NEW_TREE=$(jq -n \
148+
--arg base "$BASE_TREE" \
149+
--argjson tree "$TREE_JSON" \
150+
'{"base_tree": $base, "tree": $tree}' | \
151+
gh api "/repos/${REPO}/git/trees" --input - --jq .sha)
152+
153+
# Build commit message with DCO sign-off
154+
SIGNOFF="${app_slug}[bot] <${app_user_id}+${app_slug}[bot]@users.noreply.github.com>"
155+
COMMIT_MSG=$(printf '%s\n\n%s\n%s\n\n%s' \
156+
"chore: update guest Cargo.lock files" \
157+
"Automatically updated by dependabot-update-guest-locks workflow." \
158+
"Triggered by: ${DEPENDENCY_NAMES}" \
159+
"Signed-off-by: ${SIGNOFF}")
160+
161+
# Create commit via API — GitHub signs it automatically since we
162+
# authenticate as the App and omit custom author/committer info.
163+
NEW_COMMIT=$(jq -n \
164+
--arg msg "$COMMIT_MSG" \
165+
--arg tree "$NEW_TREE" \
166+
--arg parent "$HEAD_SHA" \
167+
'{"message": $msg, "tree": $tree, "parents": [$parent]}' | \
168+
gh api "/repos/${REPO}/git/commits" --input - --jq .sha)
169+
170+
# Update branch ref to point to the new commit
171+
gh api "/repos/${REPO}/git/refs/heads/${BRANCH}" \
172+
-X PATCH \
173+
-f sha="${NEW_COMMIT}"
174+
175+
echo "Successfully committed and pushed changes"

0 commit comments

Comments
 (0)