|
41 | 41 | fi |
42 | 42 |
|
43 | 43 | echo "All workflow action references are SHA-pinned." |
| 44 | +
|
| 45 | + - name: Verify pinned SHAs resolve |
| 46 | + env: |
| 47 | + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 48 | + run: | |
| 49 | + python - <<'PY' |
| 50 | + import os |
| 51 | + import re |
| 52 | + import sys |
| 53 | + import urllib.error |
| 54 | + import urllib.request |
| 55 | + from pathlib import Path |
| 56 | +
|
| 57 | + token = os.environ.get('GITHUB_TOKEN', '') |
| 58 | + uses_re = re.compile(r"^\s*uses:\s*([^\s#]+)") |
| 59 | + sha_re = re.compile(r"^[0-9a-fA-F]{40}$") |
| 60 | + refs = set() |
| 61 | +
|
| 62 | + for workflow in sorted(Path('.github/workflows').glob('*.yml')): |
| 63 | + for line in workflow.read_text(encoding='utf-8', errors='ignore').splitlines(): |
| 64 | + m = uses_re.match(line) |
| 65 | + if not m: |
| 66 | + continue |
| 67 | + ref = m.group(1) |
| 68 | + if ref.startswith('./') or ref.startswith('docker://'): |
| 69 | + continue |
| 70 | + if '@' not in ref: |
| 71 | + continue |
| 72 | + action, rev = ref.rsplit('@', 1) |
| 73 | + if not sha_re.fullmatch(rev): |
| 74 | + continue |
| 75 | + refs.add((action, rev, workflow.as_posix())) |
| 76 | +
|
| 77 | + if not refs: |
| 78 | + print('No pinned action SHAs found to resolve.') |
| 79 | + sys.exit(0) |
| 80 | +
|
| 81 | + headers = { |
| 82 | + 'Accept': 'application/vnd.github+json', |
| 83 | + 'User-Agent': 'workflow-action-pin-check', |
| 84 | + } |
| 85 | + if token: |
| 86 | + headers['Authorization'] = f'Bearer {token}' |
| 87 | +
|
| 88 | + failures = [] |
| 89 | + for action, rev, workflow in sorted(refs): |
| 90 | + url = f'https://api.github.com/repos/{action}/commits/{rev}' |
| 91 | + req = urllib.request.Request(url, headers=headers) |
| 92 | + try: |
| 93 | + with urllib.request.urlopen(req, timeout=20) as resp: |
| 94 | + if resp.status != 200: |
| 95 | + failures.append((workflow, action, rev, f'HTTP {resp.status}')) |
| 96 | + except urllib.error.HTTPError as exc: |
| 97 | + failures.append((workflow, action, rev, f'HTTP {exc.code}')) |
| 98 | + except Exception as exc: |
| 99 | + failures.append((workflow, action, rev, str(exc))) |
| 100 | +
|
| 101 | + if failures: |
| 102 | + print('Found unresolved pinned action SHAs:') |
| 103 | + for workflow, action, rev, reason in failures: |
| 104 | + print(f'- {workflow}: {action}@{rev} -> {reason}') |
| 105 | + sys.exit(1) |
| 106 | +
|
| 107 | + print(f'All pinned action SHAs resolved successfully ({len(refs)} refs).') |
| 108 | + PY |
0 commit comments