pvr-watchlist
$
npx mdskill add aaronjmars/aeon/pvr-watchlist> **${var}** — Optional `owner/repo` to probe on demand instead of running the full watchlist.
SKILL.md
.github/skills/pvr-watchlistView on GitHub ↗
---
name: pvr-watchlist
description: Weekly probe of repos on the security watchlist — check if private vulnerability reporting has been enabled, notify when status flips, re-submit any queued advisories or flag for re-research when draft was lost
var: ""
tags: [security, meta]
---
> **${var}** — Optional `owner/repo` to probe on demand instead of running the full watchlist.
Today is ${today}. Read `memory/MEMORY.md` before starting.
## Voice
If `soul/SOUL.md` and `soul/STYLE.md` are populated, match the operator's voice in the notification. If empty or absent, use a clear, direct, neutral tone.
## Why this skill exists
When `vuln-scanner` finds a HIGH/CRITICAL issue in a repo with no PVR, no SECURITY.md, and no reachable maintainer contact, it has no safe disclosure channel — so it logs the finding in `memory/vuln-scanned.json` as `"channel": "skipped"` and marks the advisory as pending a PVR re-check. Without a weekly probe, those findings silently age until the responsible-disclosure window closes. This skill closes that loop.
Active watchlist: `memory/security-watchlist.md`
## Steps
### 1. Load the watchlist
Read `memory/security-watchlist.md`. Parse each row in the table:
```
| owner/repo | severity | short-title | first-checked | last-checked | status |
```
If `${var}` is set, skip the file and probe only that target (one-off mode).
If the watchlist is empty or the file doesn't exist:
```
PVRL_SKIP: watchlist empty
```
Log it and stop. No notification needed.
### 2. Probe each entry for PVR status
For each repo, run:
```bash
REPO="owner/repo"
gh api "repos/${REPO}/private-vulnerability-reporting" --jq '.enabled' 2>&1
```
Expected responses:
- `true` — PVR is now enabled. **This is the flip we're watching for.**
- `false` — PVR still disabled. Note it, move on.
- `404` — Repo may have been deleted / renamed / made private. Flag as `not-found`.
- `403` — Token lacks scope or it's a private repo. Flag as `access-denied`.
**Sandbox note:** `gh` CLI handles auth internally — no token-in-URL needed. If `gh api` is blocked by the sandbox, fall back to:
```bash
curl -s -H "Authorization: Bearer $GH_GLOBAL" \
"https://api.github.com/repos/${REPO}/private-vulnerability-reporting" | grep -o '"enabled":[a-z]*'
```
### 3. Handle PVR-enabled flips
For each repo where PVR flipped to `true`:
**a) Check for a recoverable draft**
Look in `memory/pending-disclosures/` for a file whose name starts with the repo slug (replacing `/` with `-`).
```bash
SLUG=$(echo "$REPO" | tr '/' '-')
ls memory/pending-disclosures/${SLUG}*.md 2>/dev/null
```
**b) If a draft exists and status is not `shipped`:**
Attempt auto-submission via PVR API:
```bash
gh api "repos/${REPO}/security-advisories" \
--method POST \
--input <draft-content-as-json>
```
Build the JSON body from the draft file fields:
- `summary` → first heading line
- `description` → full advisory body
- `severity` → from `**Severity:**` field
- `cwe_ids` → array from `**CWE:**` field (e.g. `["CWE-639"]`)
- `vulnerabilities` → array with `{ "package": { "ecosystem": "other", "name": "$REPO" } }`
If the POST returns 201: mark draft as `status: submitted`, update `memory/vuln-scanned.json` channel to `pvr-submitted`, and note in the watchlist row `status: submitted`.
If the POST returns 403 (scope still missing): keep status as `pvr-enabled-pending-submit`. Notify operator to submit manually via the GitHub web form.
**c) If no draft exists (draft was lost):**
Do NOT attempt a blind submission. Instead, flag the entry as `pvr-enabled-needs-reresearch`: the finding needs to be re-discovered before it can be submitted. This should trigger a targeted `vuln-scanner` run on the repo.
### 4. Update the watchlist file
Rewrite `memory/security-watchlist.md` with updated `last-checked` and `status` for every entry. Status values: `pvr-disabled` | `pvr-enabled-pending-submit` | `submitted` | `not-found` | `access-denied` | `pvr-enabled-needs-reresearch`.
Remove entries where `status: submitted` AND the submission happened more than 30 days ago (they're done; lifecycle tracking is handled by `pvr-triage-monitor` from there).
### 5. Decide whether to notify
- **All entries still `pvr-disabled`:** no notification. Log counts and stop.
- **Any status flip detected (pvr-enabled, not-found, access-denied, submitted):** send notification.
- **Any `pvr-enabled-needs-reresearch`:** send urgent notification — window may be closing.
### 6. Format notification
Write to a temp file, then: `./notify -f .pending-notify-temp/pvr-watchlist-${today}.md`
```
pvr watchlist: {total} repos. {flip_count} flipped this run.
FLIPPED:
- {repo} — {severity}, PVR now enabled. {draft_status}
[draft found → auto-submitted | draft found → bot 403, manual submit needed | no draft → re-research needed]
STILL WAITING:
{n} repos still pvr-disabled. oldest: {repo} ({days}d since first scan).
watchlist: memory/security-watchlist.md
```
If a re-research is needed, escalate urgency:
```
pvr watchlist: {repo} flipped. no draft — needs re-research before the window closes.
HIGH severity. scanned {first_checked}. {days_since}d ago.
no draft on disk. need a targeted vuln-scanner run to recover the finding.
run: gh workflow run aeon.yml -f skill=vuln-scanner -f var={repo}
```
### 7. Log to memory
Append to `memory/logs/${today}.md`:
```
## PVR Watchlist
- **Watched:** {total} repos
- **Flipped:** {flip_count} ({repos_that_flipped})
- **Submitted:** {submitted_count}
- **Still waiting:** {waiting_count}
- **Notification:** {sent|skipped}
- PVRL_OK
```
## Required Env Vars
- `GH_GLOBAL` — GitHub PAT with `public_repo` + `repository_advisories:write` scope. Same token used by `vuln-scanner`. Required for cross-repo `gh api` calls.
## Sandbox Note
`gh api` uses the `GH_TOKEN` env var internally (the workflow wires `GH_GLOBAL` in). If the sandbox blocks `gh api`, use the `curl` fallback in step 2. No outbound auth-required calls except `gh api` — no pre-fetch needed.
## Watchlist File Format
`memory/security-watchlist.md` is a Markdown table maintained by this skill. Add new entries manually or via `vuln-scanner`'s "no safe channel" branch. Schema:
```markdown
# Security Watchlist
Repos where we have a staged advisory but no disclosure channel yet.
Updated automatically by pvr-watchlist skill.
| Repo | Severity | Finding | First Checked | Last Checked | Status |
|------|----------|---------|---------------|--------------|--------|
| owner/repo | HIGH | Short title | YYYY-MM-DD | YYYY-MM-DD | pvr-disabled |
```
More from aaronjmars/aeon
- [REPLACE: SKILL_NAME]Watch Vercel deploys for [REPLACE: VERCEL_PROJECT] — alert on [REPLACE: ALERT_ON] in the last [REPLACE: LOOKBACK_HOURS] hours
- Action Converter5 concrete real-life actions for today, leverage-scored against open loops with specificity and anti-fluff gates
- Agent BuzzCurated AI-agent tweets, clustered into narratives with insight summaries
- agent-displacementWeekly tracker of AI agent substitution signals — which roles, companies, and industries show real headcount displacement. Named roles + real deployments only.
- AI Framework WatchWeekly competitive-intelligence digest on the AI agent framework space — momentum, releases, breaking changes across a curated watchlist
- AIXBT PulseCross-domain market pulse from AIXBT's free grounding endpoint — crypto, macro, tradfi, geopolitics. Refreshes taxonomy references (clusters, chains) as a bonus.
- api-health-probeDaily pre-batch API provider health check — detects credit exhaustion or auth failure for every configured provider key before the morning batch runs, giving the operator a window to act before skills degrade
- Approval AuditList a wallet's live ERC-20 token approvals on Base and flag unlimited / risky spender grants. Keyless via Base RPC (eth_getLogs + eth_call) — no explorer key needed.
- article-queueWeekly article idea synthesizer — ranks signals from topic-momentum, beat-tracker, and narrative-tracker into a prioritized queue the article skill reads on next run
- atrium-catalog-watcherWeekly diff of the Atrium marketplace catalog at https://atriumhermes.tech/.well-known/skills/index.json against the prior snapshot — surfaces newly-published skills, removed skills, and updated descriptions. Supply-side complement to sparkleware-catalog (curated skill-packs.json registry) and skill-update-check (version drift of installed skills).