@@ -117,14 +117,15 @@ jobs:
117117 yarn-dedupe :
118118 runs-on : ubuntu-latest
119119 permissions :
120- contents : write
121- pull-requests : read
120+ contents : read
121+ outputs :
122+ has_changes : ${{ steps.diff.outputs.has_changes }}
122123 steps :
123124 - name : Checkout code
124125 uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
125126 with :
126- token : ${{ secrets.GITHUB_TOKEN }}
127127 fetch-depth : 0
128+ persist-credentials : false
128129
129130 - name : Setup Node.js
130131 uses : ./.github/actions/node/latest
@@ -135,9 +136,93 @@ jobs:
135136 - name : Run yarn dependencies:dedupe
136137 run : yarn dependencies:dedupe
137138
138- - name : Run yarn dedupe check
139- run : ./.github/scripts/yarn-dedupe.sh
139+ - name : Prepare yarn.lock update (same-repo PRs only; restricted paths)
140+ id : diff
141+ run : |
142+ set -euo pipefail
143+
144+ if git diff --quiet; then
145+ echo "has_changes=false" >> $GITHUB_OUTPUT
146+ exit 0
147+ fi
148+
149+ fail_message() { cat <<'EOF'
150+ ❌ The yarn.lock file needs deduplication!
151+
152+ The yarn dedupe command has modified your yarn.lock file.
153+ This means there were duplicate dependencies that could be optimized.
154+
155+ To fix this issue:
156+ 1. Run 'yarn dependencies:dedupe' locally
157+ 2. Commit the updated yarn.lock file
158+ 3. Push your changes
159+
160+ This helps keep the dependency tree clean.
161+ EOF
162+ }
163+
164+ changes="$(git diff --name-only)"
165+ if [ "$changes" != "yarn.lock" ]; then
166+ echo "Unexpected changed paths during yarn dedupe:"
167+ echo "$changes"
168+ exit 1
169+ fi
170+
171+ # Never push updates to fork PR branches, and don't auto-fix outside PRs.
172+ if [ "${{ github.event_name }}" != "pull_request" ]; then
173+ fail_message
174+ exit 1
175+ fi
176+ if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then
177+ fail_message
178+ exit 1
179+ fi
180+
181+ cp yarn.lock "${RUNNER_TEMP}/yarn.lock"
182+ echo "has_changes=true" >> $GITHUB_OUTPUT
183+
184+ - uses : actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
185+ if : steps.diff.outputs.has_changes == 'true'
186+ with :
187+ name : yarn-lock
188+ path : ${{ runner.temp }}/yarn.lock
189+ if-no-files-found : error
190+
191+ yarn-dedupe-push :
192+ if : github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && needs.yarn-dedupe.outputs.has_changes == 'true'
193+ runs-on : ubuntu-latest
194+ needs : yarn-dedupe
195+ # Security: this job has an STS-minted token, but never runs installs/builds.
196+ # It only updates yarn.lock via the GitHub API.
197+ permissions :
198+ id-token : write
199+ steps :
200+ - uses : DataDog/dd-octo-sts-action@acaa02eee7e3bb0839e4272dacb37b8f3b58ba80 # v1.0.3
201+ id : octo-sts
202+ with :
203+ scope : DataDog/dd-trace-js
204+ policy : yarn-dedupe
205+
206+ - uses : actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
207+ with :
208+ name : yarn-lock
209+ path : ${{ runner.temp }}/yarn-lock-artifact
210+
211+ - name : Update yarn.lock via GitHub API (server-created verified commit)
140212 env :
141- PR_AUTHOR : ${{ github.event.pull_request.user.login }}
142- PR_USER_TYPE : ${{ github.event.pull_request.user.type }}
143- GITHUB_EVENT_NAME : ${{ github.event_name }}
213+ GH_TOKEN : ${{ steps.octo-sts.outputs.token }}
214+ OWNER : ${{ github.repository_owner }}
215+ REPO : ${{ github.event.repository.name }}
216+ BRANCH : ${{ github.event.pull_request.head.ref }}
217+ run : |
218+ set -euo pipefail
219+
220+ test -f "${{ runner.temp }}/yarn-lock-artifact/yarn.lock"
221+ sha="$(gh api -q '.sha' "repos/${OWNER}/${REPO}/contents/yarn.lock?ref=${BRANCH}")"
222+ content="$(base64 -w 0 "${{ runner.temp }}/yarn-lock-artifact/yarn.lock")"
223+
224+ gh api -X PUT "repos/${OWNER}/${REPO}/contents/yarn.lock" \
225+ -f message="chore: deduplicate yarn.lock" \
226+ -f content="${content}" \
227+ -f sha="${sha}" \
228+ -f branch="${BRANCH}"
0 commit comments