@@ -160,10 +160,9 @@ jobs:
160160 if : github.event.pull_request.user.login == 'dependabot[bot]' && needs.vendor-build.outputs.is_vendor_group == 'true' && needs.vendor-build.outputs.has_changes == 'true'
161161 runs-on : ubuntu-latest
162162 needs : vendor-build
163- # Security: this job has write permissions but never runs installs/builds.
164- # It only applies the vetted patch artifact and pushes a single commit .
163+ # Security: this job never runs installs/builds.
164+ # It only applies the vetted patch artifact and writes the update via the GitHub API .
165165 permissions :
166- contents : write
167166 id-token : write
168167 steps :
169168 - uses : DataDog/dd-octo-sts-action@acaa02eee7e3bb0839e4272dacb37b8f3b58ba80 # v1.0.3
@@ -212,28 +211,77 @@ jobs:
212211 echo "Refusing to proceed: unexpected paths changed."
213212 exit 1
214213 fi
215- - name : Create commit
216- id : create-commit
217- run : |
218- set -euo pipefail
219-
220- git config user.name github-actions
221- git config user.email [email protected] 222-
223- git add vendor/dist vendor/package.json vendor/yarn.lock
224- git commit -m "update vendored dependencies with new versions"
225- echo "commits=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
226- - name : Push commit
214+ - name : Create verified commit via GitHub API (server-side)
227215 env :
228- DD_OCTO_STS_TOKEN : ${{ steps.octo-sts.outputs.token }}
229216 TARGET_BRANCH : ${{ github.event.pull_request.head.ref }}
217+ GH_TOKEN : ${{ steps.octo-sts.outputs.token }}
230218 run : |
231219 set -euo pipefail
232220
233- # Ensure the push is attributed to the octo-sts GitHub App token (not GITHUB_TOKEN),
234- # so the resulting push triggers CI workflows normally.
235- auth_header="AUTHORIZATION: basic $(printf 'x-access-token:%s' "$DD_OCTO_STS_TOKEN" | base64 | tr -d '\n')"
236- git -c "http.https://github.com/.extraheader=$auth_header" push origin "HEAD:$TARGET_BRANCH"
221+ repo="${GITHUB_REPOSITORY}"
222+ expected_head_oid="$(git rev-parse HEAD)"
223+
224+ max_files=200
225+ max_total_bytes=$((10 * 1024 * 1024)) # 10 MiB
226+
227+ mapfile -t changes < <(git diff --name-status)
228+ change_count="${#changes[@]}"
229+ if [ "$change_count" -eq 0 ]; then
230+ echo "No changed files detected."
231+ exit 1
232+ fi
233+ if [ "$change_count" -gt "$max_files" ]; then
234+ echo "Too many changed files ($change_count > $max_files)."
235+ exit 1
236+ fi
237+
238+ additions='[]'
239+ deletions='[]'
240+ total_bytes=0
241+ for change in "${changes[@]}"; do
242+ read -r status path path2 <<<"$change"
243+
244+ if [[ "$status" == D ]]; then
245+ deletions="$(jq -c --arg path "$path" '. + [{path: $path}]' <<<"$deletions")"
246+ continue
247+ fi
248+
249+ # Treat renames as delete+add to keep the server-side tree in sync.
250+ if [[ "$status" == R* ]]; then
251+ deletions="$(jq -c --arg path "$path" '. + [{path: $path}]' <<<"$deletions")"
252+ path="$path2"
253+ fi
254+
255+ test -f "$path"
256+ file_bytes="$(stat -c '%s' "$path")"
257+ total_bytes=$((total_bytes + file_bytes))
258+ if [ "$total_bytes" -gt "$max_total_bytes" ]; then
259+ echo "Total changes too large (${total_bytes} bytes)."
260+ exit 1
261+ fi
262+ contents="$(base64 -w 0 "$path")"
263+ additions="$(jq -c --arg path "$path" --arg contents "$contents" '. + [{path: $path, contents: $contents}]' <<<"$additions")"
264+ done
265+
266+ variables="$(jq -c \
267+ --arg repo "$repo" \
268+ --arg branch "$TARGET_BRANCH" \
269+ --arg msg "update vendored dependencies with new versions" \
270+ --arg expected "$expected_head_oid" \
271+ --argjson additions "$additions" \
272+ --argjson deletions "$deletions" \
273+ '{
274+ input: {
275+ branch: { repositoryNameWithOwner: $repo, branchName: $branch },
276+ message: { headline: $msg },
277+ expectedHeadOid: $expected,
278+ fileChanges: { additions: $additions, deletions: $deletions }
279+ }
280+ }'
281+ )"
282+
283+ query='mutation($input: CreateCommitOnBranchInput!) { createCommitOnBranch(input: $input) { commit { oid url } } }'
284+ gh api graphql -f query="$query" -f variables="$variables" -q '.data.createCommitOnBranch.commit.oid' >/dev/null
237285
238286 # If branch protection is configured to dismiss stale approvals when new commits are pushed,
239287 # the vendoring commit will invalidate the earlier approval. Re-approve and (re-)enable
0 commit comments