potiuk opened a new pull request, #290:
URL: https://github.com/apache/airflow-steward/pull/290
## Summary
CVE 5.x's `credits[]` schema has a dedicated `type: "tool"` value
exactly for the case the framework already detects: automation
that surfaced a vulnerability (scanners, AI agents, GitHub bots).
Until this PR, the framework treated all bot credit candidates the
same way: skip the credit row entirely. That under-credits real
tool contributions to the CVE record.
This PR splits the rule by **which credit field is involved**:
| Field | Before | After |
|---|---|---|
| *Reporter credited as* (finder side) | Bot detected → **skipped** | Bot
detected → **included**, generator emits `type: "tool"` |
| *Remediation developer* | Bot detected → **skipped** | Bot detected →
**skipped** (unchanged) |
The asymmetry is intentional. CVE 5.x's `credits[]` enum has `tool`
on the discovery axis but no equivalent on the remediation axis; a
Dependabot dep-bump is the automation doing what humans configured
it to do, not credit-worthy remediation. The cleanest expression
of "no human deserves remediation credit here" stays "omit the row".
### Generator change
[`tools/vulnogram/generate-cve-json/src/generate_cve_json/cve_json.py`](tools/vulnogram/generate-cve-json/src/generate_cve_json/cve_json.py):
- New `is_bot_credit(name)` predicate mirrors the policy doc's
three handle-shaped rules: literal `[bot]` suffix, known-name
whole-word match against an automation-name list, regex pattern
set (`*-bot` / `*-ai` / `*-agent` / `*-gpt` / `*scanner*` /
`*automat*`). Word boundaries (`\b`) guard against firing on
human names that happen to contain a substring (`Joe Bot` and
`Renovation Engineering` do not match).
- New `TOOL_CREDIT_TYPE = "tool"` constant.
- `build_credits()` runs `is_bot_credit()` per row in *Reporter
credited as*; matches emit `type: "tool"`, the rest stay
`type: "finder"`. *Remediation developer* rows are unaffected.
### Reframed clarification flow
The direct-reporter Gmail draft used to ask *"is `<bot>` really
how you want to be credited?"* (default: don't credit the bot
until reporter confirms). It now asks *"we've credited `<bot>` as
a tool; if a human was behind it who should also be credited as
finder, please reply with their name"*. Tool credit is the floor;
human finder is the additive ask. Via-forwarder mode behaviour
unchanged (standalone draft suppressed; question folded into
the next milestone draft).
### Tests
229 total pass (210 existing + 19 new):
- **`TestIsBotCredit`** (16 cases): `[bot]` suffix, known-name
list (case-insensitive, free-form string), pattern handles,
human-name false-positive guards, empty / whitespace edges.
- **`TestBuildCreditsBotTypeAssignment`** (6 cases): plain human
→ finder, bot suffix → tool, known name → tool, pattern handle
→ tool, mixed field → per-row, remediation-side regression
(bot stays as `type: "remediation developer"` — the asymmetric
scope is a tested property, not a side-effect).
### Files touched
| File | What |
|---|---|
| `tools/vulnogram/bot-credits-policy.md` | Rewritten *Why*, *Default
behaviour* (split into finder vs remediation subsections), *Where the rule
applies / does NOT apply*, *Worked examples*. Detection rules unchanged. |
| `tools/vulnogram/generate-cve-json/src/generate_cve_json/cve_json.py` |
`is_bot_credit()`, `TOOL_CREDIT_TYPE`, `build_credits()` routing. Module
docstring updated. |
| `tools/vulnogram/generate-cve-json/tests/test_generate_cve_json.py` |
`TestIsBotCredit` + `TestBuildCreditsBotTypeAssignment`. |
| `.claude/skills/security-issue-import/SKILL.md` | ASF-relay credit
extraction + Reporter-credited-as row → tool-credit framing. |
| `.claude/skills/security-issue-import-from-md/SKILL.md` | Reporter-line
extraction → tool-credit framing. |
| `.claude/skills/security-issue-sync/SKILL.md` | Reporter-credit mining →
tool-credit framing + reframed clarification draft. Remediation-side rules
unchanged. |
| `.claude/skills/security-issue-deduplicate/SKILL.md` | Explicit per-side
behaviour — finder rows propagate as tool credits, remediation rows still skip.
|
`.claude/skills/security-issue-import-from-pr/SKILL.md` is
unchanged — it only handles the remediation-developer side, which
keeps the skip behaviour.
### Scope
Intentionally scoped to the finder side only, per the
`type: "tool"` schema match. The remediation-developer skip rule
is the same as before; a separate change can re-litigate that if
the team decides bots ever deserve remediation credit (probably
never).
No eval fixtures needed updating — no existing case in the
security-* skill evals exercised the old finder-side skip
behaviour, so there is no expected.json drift.
## Test plan
- [x] `uv run pytest tests/` in `tools/vulnogram/generate-cve-json/` —
229 passed.
- [x] `uv run ruff check` / `ruff format --check` / `mypy` — clean.
- [x] `prek run --files <all-touched-files>` — markdownlint /
doctoc / typos / skill-validate / per-project ruff/mypy/pytest
all pass (doctoc regenerated the bot-credits-policy.md TOC
anchors for the new Finder-side / Remediation-side sub-sections).
- [ ] Next regeneration of an existing tracker whose
*Reporter credited as* contains a bot row (e.g. a historical
ASF-relay import that landed `bugbunny.ai`): verify the
emitted CVE JSON has the row with `type: "tool"`, and that
human rows alongside it stay `type: "finder"`.
- [ ] Next `security-issue-import` of an ASF-relay report with a
scanner Credit: line: verify the *Reporter credited as* field
is populated (not blank) and the Step 5 proposal shows
*"credited as tool: …"*.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]