ci: use GitHub API to produce verified commits in socket-fix workflow (#35618)
* ci: use GitHub API to produce verified commits in socket-fix workflow Replace git commit/push with the GitHub Git Data API (blobs, trees, commits) so the resulting PR commit is signed and verified by GitHub, matching the approach used in update-dep.yml. * ci: disable socket fix CI mode to prevent auto-PR creation * ci: address code review feedback on open-pr step - Add set -eEo pipefail / shopt -s inherit_errexit - Use git status --porcelain to catch new and deleted files - Read file mode from git index instead of hardcoding 100644 - Use base64 -w 0 to avoid line-wrap corruption - Handle existing branch on workflow rerun - Handle existing PR on workflow rerun - Support comma-separated issue_link for multiple GHSAs - Include WDP/Leo PR links in body when refs are provided * ci: address second round of code review feedback - Fetch HEAD_SHA from master ref via API to guard against workflow dispatch on a non-master ref - Switch to git status --porcelain=v1 -z (NUL-delimited) to handle filenames with spaces and rename/copy entries correctly - Use @<(...) process substitution for blob content to avoid hitting shell argument length limits on large files like package-lock.json * ci: fix gh pr create missing --head and rename tree deletion - Add --head "$BRANCH" to gh pr create so the PR is opened from the API-created branch rather than the currently checked-out branch - Emit a null-sha tree entry for the source path of rename operations so the old path is removed from the resulting commit
This commit is contained in:
@@ -8,7 +8,7 @@ on:
|
||||
required: true
|
||||
type: string
|
||||
issue_link:
|
||||
description: 'Link to the related security issue (e.g. https://github.com/brave/brave-browser/issues/54048)'
|
||||
description: 'Comma-separated links to related security issues (e.g. https://github.com/brave/brave-browser/issues/54048,https://github.com/brave/brave-browser/issues/54049)'
|
||||
required: true
|
||||
type: string
|
||||
wdp_ref:
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
GHSA_IDS: ${{ inputs.ghsa_ids }}
|
||||
SOCKET_SECURITY_API_KEY: ${{ secrets.SOCKET_SECURITY_API_KEY }}
|
||||
SOCKET_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CI: 'true'
|
||||
CI: ''
|
||||
run: |
|
||||
if ! [[ "$GHSA_IDS" =~ ^GHSA-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}(,[[:space:]]?GHSA-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4})*$ ]]; then
|
||||
echo "::error::GHSA_IDS contains invalid entries. Expected format: GHSA-xxxx-xxxx-xxxx (comma or comma-space separated)"
|
||||
@@ -77,23 +77,103 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GHSA_IDS: ${{ inputs.ghsa_ids }}
|
||||
ISSUE_LINK: ${{ inputs.issue_link }}
|
||||
WDP_REF: ${{ inputs.wdp_ref }}
|
||||
LEO_REF: ${{ inputs.leo_ref }}
|
||||
run: |
|
||||
if ! git diff --quiet; then
|
||||
BRANCH="socket-fix/$(echo "$GHSA_IDS" | tr ', ' '-' | tr -s '-' | cut -c1-60)"
|
||||
git config user.name "brave-builds"
|
||||
git config user.email "devops@brave.com"
|
||||
git checkout -b "$BRANCH"
|
||||
git add -A
|
||||
git commit -m "fix: address security advisories"
|
||||
git push origin "$BRANCH"
|
||||
BODY="Addresses: $GHSA_IDS"$'\n\n'"closes $ISSUE_LINK"
|
||||
gh pr create \
|
||||
--title "fix: address security advisories" \
|
||||
--body "$BODY" \
|
||||
--base master \
|
||||
--label "CI/skip" \
|
||||
--label "security"
|
||||
else
|
||||
shopt -s inherit_errexit
|
||||
set -eEo pipefail
|
||||
|
||||
if [ -z "$(git status --porcelain)" ]; then
|
||||
echo "::error::No changes produced by socket fix."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BRANCH="socket-fix/$(echo "$GHSA_IDS" | tr ', ' '-' | tr -s '-' | cut -c1-60)"
|
||||
HEAD_SHA=$(gh api "/repos/${GITHUB_REPOSITORY}/git/refs/heads/master" -q '.object.sha')
|
||||
|
||||
if gh api "repos/${GITHUB_REPOSITORY}/git/refs/heads/$BRANCH" -q .ref > /dev/null 2>&1; then
|
||||
gh api --method PATCH "/repos/${GITHUB_REPOSITORY}/git/refs/heads/$BRANCH" \
|
||||
--field sha="$HEAD_SHA" --field force=true
|
||||
else
|
||||
gh api --method POST /repos/${GITHUB_REPOSITORY}/git/refs \
|
||||
--field ref="refs/heads/$BRANCH" --field sha="$HEAD_SHA"
|
||||
fi
|
||||
|
||||
TREE_JSON="[]"
|
||||
while IFS= read -r -d $'\0' line; do
|
||||
XY="${line:0:2}"
|
||||
FILE="${line:3}"
|
||||
# For rename/copy entries the old path follows as the next NUL entry;
|
||||
# emit a deletion for it so the source path is removed from the tree.
|
||||
if [[ "${XY:0:1}" =~ [RC] ]]; then
|
||||
IFS= read -r -d $'\0' _old_path
|
||||
if [[ "${XY:0:1}" == "R" ]]; then
|
||||
TREE_JSON=$(jq --arg path "$_old_path" \
|
||||
'. += [{"path": $path, "mode": "100644", "type": "blob", "sha": null}]' \
|
||||
<<< "$TREE_JSON")
|
||||
fi
|
||||
fi
|
||||
if [[ "${XY:1:1}" == "D" ]]; then
|
||||
TREE_JSON=$(jq --arg path "$FILE" \
|
||||
'. += [{"path": $path, "mode": "100644", "type": "blob", "sha": null}]' \
|
||||
<<< "$TREE_JSON")
|
||||
else
|
||||
MODE=$(git ls-files -s -- "$FILE" | awk 'NR==1 { print $1 }')
|
||||
[[ -z "$MODE" ]] && MODE="100644"
|
||||
if [[ "$MODE" == "120000" ]]; then
|
||||
BLOB_SHA=$(gh api --method POST /repos/${GITHUB_REPOSITORY}/git/blobs \
|
||||
--field content=@<(printf '%s' "$(readlink -- "$FILE")" | base64 -w 0) \
|
||||
--field encoding=base64 \
|
||||
-q .sha)
|
||||
else
|
||||
BLOB_SHA=$(gh api --method POST /repos/${GITHUB_REPOSITORY}/git/blobs \
|
||||
--field content=@<(base64 -w 0 -- "$FILE") \
|
||||
--field encoding=base64 \
|
||||
-q .sha)
|
||||
fi
|
||||
TREE_JSON=$(jq --arg path "$FILE" --arg mode "$MODE" --arg sha "$BLOB_SHA" \
|
||||
'. += [{"path": $path, "mode": $mode, "type": "blob", "sha": $sha}]' \
|
||||
<<< "$TREE_JSON")
|
||||
fi
|
||||
done < <(git status --porcelain=v1 -z)
|
||||
|
||||
BASE_TREE=$(gh api /repos/${GITHUB_REPOSITORY}/git/commits/"$HEAD_SHA" -q .tree.sha)
|
||||
|
||||
NEW_TREE_SHA=$(jq -n \
|
||||
--arg base_tree "$BASE_TREE" \
|
||||
--argjson tree "$TREE_JSON" \
|
||||
'{"base_tree": $base_tree, "tree": $tree}' | \
|
||||
gh api --method POST /repos/${GITHUB_REPOSITORY}/git/trees --input - -q .sha)
|
||||
|
||||
NEW_COMMIT_SHA=$(jq -n \
|
||||
--arg tree "$NEW_TREE_SHA" \
|
||||
--arg parent "$HEAD_SHA" \
|
||||
'{"message": "fix: address security advisories", "tree": $tree, "parents": [$parent]}' | \
|
||||
gh api --method POST /repos/${GITHUB_REPOSITORY}/git/commits --input - -q .sha)
|
||||
|
||||
gh api --method PATCH /repos/${GITHUB_REPOSITORY}/git/refs/heads/"$BRANCH" \
|
||||
--field sha="$NEW_COMMIT_SHA"
|
||||
|
||||
BODY="Addresses: $GHSA_IDS"
|
||||
IFS=',' read -ra LINKS <<< "$ISSUE_LINK"
|
||||
for link in "${LINKS[@]}"; do
|
||||
BODY="$BODY"$'\n\n'"closes ${link// /}"
|
||||
done
|
||||
if [[ -n "$WDP_REF" ]]; then
|
||||
WDP_PR=$(gh api "repos/brave/web-discovery-project/commits/$WDP_REF/pulls" -q '.[0].html_url' 2>/dev/null || true)
|
||||
[[ -n "$WDP_PR" ]] && BODY="$BODY"$'\n\n'"WDP: $WDP_PR"
|
||||
fi
|
||||
if [[ -n "$LEO_REF" ]]; then
|
||||
LEO_PR=$(gh api "repos/brave/leo/commits/$LEO_REF/pulls" -q '.[0].html_url' 2>/dev/null || true)
|
||||
[[ -n "$LEO_PR" ]] && BODY="$BODY"$'\n\n'"Leo: $LEO_PR"
|
||||
fi
|
||||
if ! gh pr list --repo "${GITHUB_REPOSITORY}" --head "$BRANCH" --json number -q '.[].number' | grep -q .; then
|
||||
gh pr create \
|
||||
--repo "${GITHUB_REPOSITORY}" \
|
||||
--title "fix: address security advisories" \
|
||||
--body "$BODY" \
|
||||
--head "$BRANCH" \
|
||||
--base master \
|
||||
--label "CI/skip" \
|
||||
--label "security"
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user