Skip to content

Commit b6797ed

Browse files
authored
feat(ci): add upstream CometBFT watcher workflow (#2961)
## Summary Adds `.github/workflows/upstream-cometbft-watcher.yml`, a daily GitHub Actions workflow that files a triage issue in this repo when upstream [`cometbft/cometbft`](https://github.com/cometbft/cometbft) publishes a release on the tracked version line (`v0.38.x`) or a new security advisory. - Uses the built-in `GITHUB_TOKEN` — no new secrets required. - Idempotent via GitHub issue title search (no local state file). - Supports `workflow_dispatch` with a `dry_run` input for verification. - `advisories` and `releases` watchers run in parallel after `ensure-labels`, so a failure in one API endpoint doesn't block the other. ## Why `v0.38.x`? All three active celestia-core branches (`main`, `v0.39.x-celestia`, `v0.38.x-celestia`) currently track upstream CometBFT **v0.38.x**. When `main` advances to a newer upstream line, update the `TRACKED_PREFIX` env var in the workflow. ## Test plan - [x] `actionlint` passes on the workflow. - [x] Local simulation of both watchers against live `cometbft/cometbft` APIs returned the expected data (12 published advisories, 13 `v0.38.*` releases in the last 100), with the tightened idempotency search correctly reporting 0 existing issues. - [x] Review feedback addressed: decoupled `releases` from `advisories` so the two watchers run independently. - [ ] GitHub's `workflow_dispatch` API can only look up a workflow by filename once the file exists on the default branch. After merge, trigger a first run via: ``` gh workflow run upstream-cometbft-watcher.yml --ref main -f dry_run=true ``` and confirm the advisory and release watchers list the expected items without creating issues. Then let the 13:00 UTC cron file catch-up issues for currently-unseen upstream items. Closes #2789 Closes https://linear.app/celestia/issue/PROTOCO-1030 🤖 Generated with [Claude Code](https://claude.com/claude-code)
1 parent d320c7c commit b6797ed

2 files changed

Lines changed: 210 additions & 0 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- [ci] \#2789 Add `upstream-cometbft-watcher` GitHub Actions workflow
2+
that files a triage issue when upstream CometBFT publishes a release
3+
on the tracked version line or a new security advisory.
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
name: upstream-cometbft-watcher
2+
3+
on:
4+
schedule:
5+
# 13:00 UTC daily
6+
- cron: '0 13 * * *'
7+
workflow_dispatch:
8+
inputs:
9+
dry_run:
10+
description: 'Log actions without creating issues'
11+
type: boolean
12+
default: false
13+
14+
permissions:
15+
issues: write
16+
contents: read
17+
18+
env:
19+
UPSTREAM_REPO: cometbft/cometbft
20+
TARGET_REPO: ${{ github.repository }}
21+
TRACKED_PREFIX: 'v0.38.'
22+
DRY_RUN: ${{ inputs.dry_run == true && 'true' || 'false' }}
23+
24+
jobs:
25+
ensure-labels:
26+
runs-on: ubuntu-latest
27+
steps:
28+
- name: Ensure labels exist
29+
env:
30+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
31+
run: |
32+
set -euo pipefail
33+
gh label create upstream-cometbft \
34+
--repo "$TARGET_REPO" \
35+
--color '0E8A16' \
36+
--description 'Upstream CometBFT release or advisory that needs triage' \
37+
--force
38+
gh label create security \
39+
--repo "$TARGET_REPO" \
40+
--color 'D93F0B' \
41+
--description 'Security-related issue' \
42+
--force
43+
44+
advisories:
45+
needs: ensure-labels
46+
runs-on: ubuntu-latest
47+
steps:
48+
- name: File issues for new upstream advisories
49+
env:
50+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
51+
run: |
52+
set -euo pipefail
53+
54+
# Fetch all published advisories (compact JSON, one per line). Capturing
55+
# to a variable first so a failed API call fails the job via set -e
56+
# instead of being swallowed by the process substitution below.
57+
advisories_raw=$(
58+
gh api "/repos/${UPSTREAM_REPO}/security-advisories" --paginate \
59+
--jq '.[] | select(.state=="published") | {ghsa_id, summary, severity, published_at, html_url} | @json'
60+
)
61+
62+
if [ -z "$advisories_raw" ]; then
63+
echo "No published advisories found on ${UPSTREAM_REPO}."
64+
exit 0
65+
fi
66+
67+
mapfile -t advisories <<< "$advisories_raw"
68+
69+
for advisory_json in "${advisories[@]}"; do
70+
[ -n "$advisory_json" ] || continue
71+
ghsa_id=$(echo "$advisory_json" | jq -r .ghsa_id)
72+
summary=$(echo "$advisory_json" | jq -r .summary)
73+
severity=$(echo "$advisory_json" | jq -r .severity)
74+
published=$(echo "$advisory_json" | jq -r .published_at)
75+
url=$(echo "$advisory_json" | jq -r .html_url)
76+
77+
title="Upstream CometBFT advisory: ${ghsa_id}"
78+
79+
# Idempotency: narrow the search by the unique GHSA ID and post-filter
80+
# with an exact title match via jq --arg (safe against special chars).
81+
existing=$(
82+
gh issue list --repo "$TARGET_REPO" \
83+
--search "in:title ${ghsa_id}" \
84+
--state all --limit 100 \
85+
--json title \
86+
| jq --arg t "$title" '[.[] | select(.title == $t)] | length'
87+
)
88+
if [ "$existing" -gt 0 ]; then
89+
echo "Skipping (already exists): ${title}"
90+
continue
91+
fi
92+
93+
body=$(cat <<EOF
94+
Upstream CometBFT published a new security advisory.
95+
96+
- **GHSA ID:** ${ghsa_id}
97+
- **Severity:** ${severity}
98+
- **Published:** ${published}
99+
- **Link:** ${url}
100+
101+
## Summary
102+
103+
${summary}
104+
105+
## Checklist
106+
107+
- [ ] Assess applicability to celestia-core (\`main\`, \`v0.39.x-celestia\`, \`v0.38.x-celestia\`)
108+
- [ ] Backport any applicable fixes
109+
- [ ] Close this issue when triage is complete
110+
111+
_Filed automatically by \`.github/workflows/upstream-cometbft-watcher.yml\`._
112+
EOF
113+
)
114+
115+
if [ "$DRY_RUN" = "true" ]; then
116+
echo "[dry-run] Would create issue: ${title}"
117+
continue
118+
fi
119+
120+
gh issue create \
121+
--repo "$TARGET_REPO" \
122+
--title "$title" \
123+
--label upstream-cometbft \
124+
--label security \
125+
--body "$body"
126+
done
127+
128+
releases:
129+
needs: ensure-labels
130+
runs-on: ubuntu-latest
131+
steps:
132+
- name: File issues for new upstream releases
133+
env:
134+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
135+
run: |
136+
set -euo pipefail
137+
138+
# Fetch last 100 upstream releases (non-draft, non-prerelease, tag starts
139+
# with TRACKED_PREFIX). Capturing to a variable first so a failed API
140+
# call fails the job via set -e instead of being swallowed.
141+
releases_raw=$(
142+
gh release list --repo "$UPSTREAM_REPO" --limit 100 \
143+
--json tagName,publishedAt,isDraft,isPrerelease \
144+
| jq -c --arg prefix "$TRACKED_PREFIX" \
145+
'.[] | select(.isDraft==false and .isPrerelease==false) | select(.tagName | startswith($prefix))'
146+
)
147+
148+
if [ -z "$releases_raw" ]; then
149+
echo "No releases on ${UPSTREAM_REPO} matching prefix ${TRACKED_PREFIX}."
150+
exit 0
151+
fi
152+
153+
mapfile -t releases <<< "$releases_raw"
154+
155+
for release_json in "${releases[@]}"; do
156+
[ -n "$release_json" ] || continue
157+
tag=$(echo "$release_json" | jq -r .tagName)
158+
published=$(echo "$release_json" | jq -r .publishedAt)
159+
url="https://github.com/${UPSTREAM_REPO}/releases/tag/${tag}"
160+
161+
title="Upstream CometBFT release: ${tag}"
162+
163+
# Idempotency: narrow the search by the unique tag and post-filter
164+
# with an exact title match via jq --arg (safe against special chars).
165+
existing=$(
166+
gh issue list --repo "$TARGET_REPO" \
167+
--search "in:title ${tag}" \
168+
--state all --limit 100 \
169+
--json title \
170+
| jq --arg t "$title" '[.[] | select(.title == $t)] | length'
171+
)
172+
if [ "$existing" -gt 0 ]; then
173+
echo "Skipping (already exists): ${title}"
174+
continue
175+
fi
176+
177+
body=$(cat <<EOF
178+
Upstream CometBFT published a new release on the \`${TRACKED_PREFIX}x\` line.
179+
180+
- **Tag:** ${tag}
181+
- **Published:** ${published}
182+
- **Link:** ${url}
183+
184+
## Checklist
185+
186+
- [ ] Read the release notes
187+
- [ ] Assess applicability to celestia-core (\`main\`, \`v0.39.x-celestia\`, \`v0.38.x-celestia\`)
188+
- [ ] Backport any security-relevant or bug-fix commits
189+
- [ ] Close this issue when triage is complete
190+
191+
See also: [open \`upstream-cometbft\` issues](https://github.com/${TARGET_REPO}/issues?q=is%3Aissue+is%3Aopen+label%3Aupstream-cometbft) for advisories to cross-reference.
192+
193+
_Filed automatically by \`.github/workflows/upstream-cometbft-watcher.yml\`._
194+
EOF
195+
)
196+
197+
if [ "$DRY_RUN" = "true" ]; then
198+
echo "[dry-run] Would create issue: ${title}"
199+
continue
200+
fi
201+
202+
gh issue create \
203+
--repo "$TARGET_REPO" \
204+
--title "$title" \
205+
--label upstream-cometbft \
206+
--body "$body"
207+
done

0 commit comments

Comments
 (0)