Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/scripts/update-spm-pin.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
# Pins the AccessibilityDevTools dependency in the synthetic Package.swift that
# scripts/{bash,zsh,fish}/spm.sh generate to an immutable commit SHA, and
# regenerates each script's .sha256 self-update sidecar (DEVA11Y-477 / F-005).
#
# Usage: .github/scripts/update-spm-pin.sh [<40-char sha>]
# With no argument, pins to the latest first-parent commit on origin/main that
# touched the plugin itself (Package.swift or Plugins/). Commits that only touch
# scripts/ (including the pin bumps this produces) never move that SHA, so a
# merged bump cannot trigger another bump.
#
# Prints the pinned SHA. Run from the repository root.
set -euo pipefail

SCRIPTS=(scripts/bash/spm.sh scripts/zsh/spm.sh scripts/fish/spm.sh)
DEP_URL='https://github.com/browserstack/AccessibilityDevTools.git'

sha="${1:-$(git log -1 --first-parent --format=%H origin/main -- Package.swift Plugins)}"
if ! printf '%s' "$sha" | grep -Eq '^[0-9a-f]{40}$'; then
echo "error: '${sha}' is not a full 40-character commit SHA" >&2
exit 1
fi

sha256_of() {
if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | awk '{print $1}'
else shasum -a 256 "$1" | awk '{print $1}'; fi
}

for script in "${SCRIPTS[@]}"; do
# Replace whatever requirement the dependency line has today (branch: "main" or
# a previous revision: "<sha>") with the new revision pin.
sed -E "s#(\\.package\\(url: \"${DEP_URL}\", )(branch|revision): \"[^\"]*\"\\)#\\1revision: \"${sha}\")#" \
"$script" > "${script}.tmp"
if ! grep -Fq ".package(url: \"${DEP_URL}\", revision: \"${sha}\")" "${script}.tmp"; then
rm -f "${script}.tmp"
echo "error: dependency line not found in ${script}" >&2
exit 1
fi
cat "${script}.tmp" > "$script" # keep the original file mode
rm -f "${script}.tmp"
printf '%s %s\n' "$(sha256_of "$script")" "$(basename "$script")" > "${script}.sha256"
done

echo "$sha"
140 changes: 140 additions & 0 deletions .github/workflows/spm-pin-bump.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
name: SPM dependency pin

# scripts/{bash,zsh,fish}/spm.sh generate a throwaway Package.swift that depends on
# this repository. It used to track `branch: "main"`, so every scan resolved
# whatever HEAD of main was at that moment (DEVA11Y-477 / F-005, CWE-829). It is
# now pinned to an immutable `revision:` SHA, and this workflow keeps that pin
# current without going back to a mutable ref:
#
# bump — when plugin code (Package.swift / Plugins/) lands on main, runs
# .github/scripts/update-spm-pin.sh and opens (or refreshes) a PR moving
# the pin to that commit. The bump goes through review like any other
# change, so a bad commit on main does not reach users automatically.
# Bump PRs only touch scripts/, so merging one never moves the pin again.
# guard — on PRs touching scripts/, fails if any spm.sh stops pinning to a full
# 40-char revision (e.g. a revert back to `branch: "main"`).
#
# PRs opened with the default GITHUB_TOKEN do not trigger other workflows, so the
# required checks will not start on them on their own. Set a PIN_BUMP_TOKEN secret
# (GitHub App installation token or fine-grained PAT with contents + pull-requests
# write) to have them run; without it, close/reopen the bump PR to start checks.

on:
push:
branches: [main]
paths:
- 'Package.swift'
- 'Plugins/**'
pull_request:
paths:
- 'scripts/**'
- '.github/scripts/update-spm-pin.sh'
- '.github/workflows/spm-pin-bump.yml'
schedule:
- cron: '0 6 * * 1' # weekly safety net in case a push run was missed
workflow_dispatch:

permissions:
contents: read

jobs:
bump:
name: Open PR bumping the SPM pin
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: write
pull-requests: write
concurrency:
group: spm-pin-bump
cancel-in-progress: false
env:
BUMP_BRANCH: ci/spm-pin-bump
GH_TOKEN: ${{ secrets.PIN_BUMP_TOKEN || github.token }}
steps:
- name: Checkout main (full history to find the latest plugin commit)
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: main
fetch-depth: 0
token: ${{ secrets.PIN_BUMP_TOKEN || github.token }}

- name: Update pin in spm.sh scripts and sidecars
id: pin
run: |
set -euo pipefail
old=$(grep -oE 'AccessibilityDevTools\.git", revision: "[0-9a-f]{40}"' scripts/bash/spm.sh \
| grep -oE '[0-9a-f]{40}' || true)
new=$(.github/scripts/update-spm-pin.sh)
echo "old=${old}" >> "$GITHUB_OUTPUT"
echo "new=${new}" >> "$GITHUB_OUTPUT"
if git diff --quiet; then
echo "Pin already at ${new}; nothing to do."
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
fi

- name: Push bump branch and open/update PR
if: steps.pin.outputs.changed == 'true'
env:
OLD: ${{ steps.pin.outputs.old }}
NEW: ${{ steps.pin.outputs.new }}
run: |
set -euo pipefail
short="${NEW:0:12}"
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git switch -C "$BUMP_BRANCH"
git commit -qam "chore(spm): pin AccessibilityDevTools dependency to ${short} (DEVA11Y-477)"
# The bump branch is bot-owned and always rebuilt from main.
git push --force origin "HEAD:refs/heads/${BUMP_BRANCH}"

{
echo "Moves the \`revision:\` pin in the Package.swift generated by \`scripts/{bash,zsh,fish}/spm.sh\` to \`${NEW}\`, the latest commit on \`main\` that changed the plugin, and regenerates the \`.sha256\` self-update sidecars."
echo
if [ -n "$OLD" ]; then
echo "Plugin changes since the previous pin \`${OLD:0:12}\`:"
echo
echo '```'
git log --first-parent --format='%h %s' "${OLD}..${NEW}" -- Package.swift Plugins
echo '```'
echo
fi
echo "Review those changes before merging: once merged, every \`spm.sh\` scan resolves the plugin at this commit."
echo
echo "Opened automatically by \`.github/workflows/spm-pin-bump.yml\` (DEVA11Y-477)."
} > "$RUNNER_TEMP/pr-body.md"

pr=$(gh pr list --head "$BUMP_BRANCH" --base main --state open --json number --jq '.[0].number // empty')
if [ -n "$pr" ]; then
gh pr edit "$pr" --title "chore(spm): pin AccessibilityDevTools dependency to ${short}" --body-file "$RUNNER_TEMP/pr-body.md"
echo "Updated PR #${pr}"
else
gh pr create --base main --head "$BUMP_BRANCH" \
--title "chore(spm): pin AccessibilityDevTools dependency to ${short}" \
--body-file "$RUNNER_TEMP/pr-body.md"
fi

guard:
name: spm.sh pins a full commit SHA
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Require revision pin in every spm.sh
run: |
set -uo pipefail
status=0
for script in scripts/bash/spm.sh scripts/zsh/spm.sh scripts/fish/spm.sh; do
if grep -Eq '\.package\(url: "https://github\.com/browserstack/AccessibilityDevTools\.git", revision: "[0-9a-f]{40}"\)' "$script"; then
echo "OK $script"
else
echo "FAILED $script must pin AccessibilityDevTools with revision: \"<40-char sha>\" (DEVA11Y-477); run .github/scripts/update-spm-pin.sh"
status=1
fi
done
Comment thread
Crash0v3rrid3 marked this conversation as resolved.
exit "$status"
2 changes: 1 addition & 1 deletion scripts/bash/spm.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/usr/bin/env bash -il

GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
Expand Down Expand Up @@ -112,7 +112,7 @@
let package = Package(
name: "Dummy",
dependencies: [
.package(url: "https://github.com/browserstack/AccessibilityDevTools.git", branch: "main")
.package(url: "https://github.com/browserstack/AccessibilityDevTools.git", revision: "806f98cb0e8a93656e52aba6394b9366ec0c5b3b")
],
targets: []
)
Expand Down
2 changes: 1 addition & 1 deletion scripts/bash/spm.sh.sha256
Original file line number Diff line number Diff line change
@@ -1 +1 @@
b520c458bec538505c9ff9ca75a02ec901597fd66b3c2d951b928e58e58e60da spm.sh
6ec53f99f4976f5769c094e015fa99a9eb92cac406a7379fb1c0ef8d166bdf88 spm.sh
2 changes: 1 addition & 1 deletion scripts/fish/spm.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/usr/bin/env bash -il

export PATH="$PATH:/opt/homebrew/bin"
Expand Down Expand Up @@ -125,7 +125,7 @@
let package = Package(
name: "Dummy",
dependencies: [
.package(url: "https://github.com/browserstack/AccessibilityDevTools.git", branch: "main")
.package(url: "https://github.com/browserstack/AccessibilityDevTools.git", revision: "806f98cb0e8a93656e52aba6394b9366ec0c5b3b")
],
targets: []
)
Expand Down
2 changes: 1 addition & 1 deletion scripts/fish/spm.sh.sha256
Original file line number Diff line number Diff line change
@@ -1 +1 @@
982bbb10bb9bd55428208454a766384fae58c41dacabb1e5b8a74d2366f0d1e7 spm.sh
07afdbe6582a562721f297eb5773cb5dd21b78e3ecb5de9f806ed07201aeafa3 spm.sh
2 changes: 1 addition & 1 deletion scripts/zsh/spm.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/usr/bin/env bash -il

# Shell specific
Expand Down Expand Up @@ -124,7 +124,7 @@
let package = Package(
name: "Dummy",
dependencies: [
.package(url: "https://github.com/browserstack/AccessibilityDevTools.git", branch: "main")
.package(url: "https://github.com/browserstack/AccessibilityDevTools.git", revision: "806f98cb0e8a93656e52aba6394b9366ec0c5b3b")
],
targets: []
)
Expand Down
2 changes: 1 addition & 1 deletion scripts/zsh/spm.sh.sha256
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1f28d5b3025636d9b81299032f34886f8804b1c6c95b830204325b325bd1d84f spm.sh
e2e9c9104892cbcca63edd3664783b058272d396efa03028a0083ae3789de90e spm.sh
Loading