Skip to content

Disclosure clock

Disclosure clock #16

name: Disclosure clock
on:
schedule:
- cron: '0 13 * * *'
workflow_dispatch:
permissions:
contents: write
issues: write
pull-requests: write
# A manual dispatch overlapping the cron run would double-file warning issues
# and race on branch creation. Queue instead of cancel: a half-run clock leaves
# a branch pushed with no PR opened.
concurrency:
group: disclosure-clock
cancel-in-progress: false
jobs:
clock:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.13'
cache: pip
- run: pip install -r requirements.txt
- name: Compute the work queue
id: queue
run: |
python -m tools.clock_report > /tmp/clock.json
cat /tmp/clock.json
- name: Warn seven days out
env:
GH_TOKEN: ${{ github.token }}
run: |
for row in $(jq -r '.warn[] | @base64' /tmp/clock.json); do
get() { echo "$row" | base64 -d | jq -r ".$1"; }
id="$(get endor_id)"
# All states: an open-only list refiles this daily once closed.
# Titles are compared field by field rather than passed to --search,
# whose full-text index tokenizes on hyphens: a search for
# EL-2026-001 also matches a title holding EL-2026-0012 and would
# silently suppress a warning that is actually due.
existing="$(gh issue list --state all --label disclosure-clock \
--limit 500 --json title \
| jq --arg id "$id" '[.[] | select((.title | split(" ")[0]) == $id)] | length')"
if [ "$existing" != "0" ]; then
echo "$id already warned"
continue
fi
gh issue create \
--title "$id deadline in $(get days_remaining) days" \
--label disclosure-clock \
--body "$(printf '@p80n-sec — disclosure deadline approaching.\n\n- Reference: %s\n- Project: %s\n- Reported: %s\n- Deadline expires: %s\n\nGather before the publish PR opens:\n\n- [ ] CVE or GHSA identifier\n- [ ] CVSS score\n- [ ] Title\n- [ ] Endor reference URL\n- [ ] Writeup link\n- [ ] Talk slug, if any\n\nEvery fact above is already public in the pending table on the site.' \
"$id" "$(get project)" "$(get reported)" "$(get deadline)")"
done
- name: Open publish-prep PRs at expiry
env:
GH_TOKEN: ${{ github.token }}
run: |
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
for row in $(jq -r '.expire[] | @base64' /tmp/clock.json); do
get() { echo "$row" | base64 -d | jq -r ".$1"; }
id="$(get endor_id)"
key="$(get key)"
branch="disclosure/${id}-publish"
if git ls-remote --exit-code --heads origin "$branch" >/dev/null 2>&1; then
echo "$branch already exists"
continue
fi
# Every step below skips only this record on failure. Under bash -e
# a bare failure kills the step, and the loop never reaches the
# records after it — so one bad row starves every later one, every
# day. -f discards any leftovers from a skipped record.
git checkout -f -B "$branch" origin/main || { echo "cannot branch for $id"; continue; }
python -m tools.scaffold_publish "$key" || { echo "cannot scaffold $key"; continue; }
git add -A || { echo "cannot stage $key"; continue; }
# scaffold_publish is idempotent, so a record that already carries
# the TODO block stages nothing and git commit would exit 1.
if git diff --cached --quiet; then
echo "$key already scaffolded, skipping"
continue
fi
git commit -m "Scaffold publish TODOs for $id after disclosure deadline [skip ci]" \
|| { echo "cannot commit $key"; continue; }
git push -u origin "$branch" || { echo "cannot push $branch"; continue; }
gh pr create --base main --head "$branch" \
--title "Prepare $id for publication — disclosure deadline expired" \
--body "$(printf '@p80n-sec — the %s day window on %s has expired.\n\nThis PR adds a TODO block to the record. It does not publish anything by itself: status stays in-progress and the published table does not change until a human fills in the TODOs, flips status to published, and merges.\n\n- [ ] Replace the TODO identifier with the real CVE or GHSA\n- [ ] Set the real CVSS score\n- [ ] Set the title\n- [ ] Set disclosed to the actual disclosure date\n- [ ] Add refs.nvd and refs.endor\n- [ ] Add the writeup link\n- [ ] Flip status to published\n- [ ] Rename findings/%s to the CVE-keyed folder name\n' \
"90+30" "$id" "$key")" \
|| { echo "cannot open a PR for $branch"; continue; }
done