Skip to content

feat(security): add a finder-credit policy — timing gate and no placeholders - #1127

Merged
potiuk merged 1 commit into
apache:mainfrom
potiuk:fix/finder-credit-pr-already-open
Aug 29, 2026
Merged

feat(security): add a finder-credit policy — timing gate and no placeholders#1127
potiuk merged 1 commit into
apache:mainfrom
potiuk:fix/finder-credit-pr-already-open

Conversation

@potiuk

@potiuk potiuk commented Aug 29, 2026

Copy link
Copy Markdown
Member

Summary

The framework has no answer to "does this report earn a finder credit at all?". bot-credits-policy.md decides what category a credited party belongs to; nothing decides whether the credit is earned, and nothing says how to represent the absence of a finder.

Adds tools/cve-tool-vulnogram/finder-credit-policy.md as its sibling, with two rules.

Rule 1 — timing. No finder credit when a public fix PR for the same issue was already opened before the report arrived. The bar is opened, not merged: an open PR's diff, title and touched code path are readable by anyone, so a later report is not telling the project something it did not already know. Two authoritative timestamps decide it (gh pr view --json createdAt, the inbound Date: header) — never the reporter's prose. Four exceptions: the original finder, a genuinely different prong, a credit already offered in writing, a credit already published.

Rule 2 — no placeholders. Where there is no named finder, omit the finder credit rather than writing anonymous. An empty field makes the generator emit no finder entry, which is the correct record — a credits[] carrying only the remediation developer is normal and complete. Rule 2 governs only the finder row; a tool that made the discovery is still credited type: "tool".

Motivation

Both rules come from a downstream adopter that hit the failure modes directly. Rule 1's written-offer exception is the load-bearing one: that adopter credited a duplicate reporter, then had to retract it once the rule was drawn. Applying the gate at intake — before any offer is made — is what stops the retraction being necessary.

Rule 2 comes from an ASF CVE reviewer's feedback on a published batch: "I'm not sure how helpful it is to credit 'anonymous' as finder, just leave it out."

Relationship to #1124

#1124 (open) makes anonymous the fallback when a scanner declares no public credit name. Rule 2 supersedes that fallback — the right end state is to omit the finder row, not write a placeholder. Rather than growing #1124's scope after review, I'll rebase this branch once #1124 merges and change that one fallback phrase to match. Flagging it so a reviewer seeing both doesn't read it as a contradiction.

Scope

Wired into the two skills that actually write the field — security-issue-import (intake) and security-issue-sync (reconciliation) — and cross-referenced from bot-credits-policy.md. security-cve-allocate and security-issue-deduplicate appear in the policy's applies-to list but aren't edited: neither writes credits[] directly.

Test plan

prek run --files passes on all four files — markdownlint, typos, check-placeholders, skill-and-tool-validate, doctoc, SPDX stamping, and the in-hook lychee. The new doc uses only <upstream> / <N> placeholders (no project identity), which check-placeholders verifies. The worked example is fully anonymised.

🤖 Generated with Claude Code

…holders

The framework had no answer to "does this report earn a `finder` credit
at all?". `bot-credits-policy.md` decides what *category* a credited
party belongs to, but nothing decided whether the credit is earned, and
nothing said how to represent the absence of a finder.

Adds `tools/cve-tool-vulnogram/finder-credit-policy.md` as its sibling,
carrying two rules.

Rule 1 — timing. A report earns no finder credit when a public fix PR
for the same issue was already *opened* before the report arrived. The
bar is opened, not merged: an open PR's diff, title, and touched code
path are readable by anyone, so a later report is not telling the
project something it did not already know. Two authoritative timestamps
decide it (`gh pr view --json createdAt` and the inbound `Date:`
header), never the reporter's prose. Four exceptions: the original
finder, a genuinely different prong, a credit already offered in
writing, and a credit already published.

The written-offer exception is the load-bearing one. Withdrawing a
credit a reporter has read costs the project far more than one credit
line, and the reporter did nothing to deserve it — so the gate is
applied at intake, before any offer is made, and an offer made in error
is the project's to absorb.

Rule 2 — no placeholders. Where there is no named finder, omit the
`finder` credit rather than writing `anonymous`. An empty field makes
the generator emit no `finder` entry, which is the correct record: a
`credits[]` carrying only the remediation developer is normal and
complete. A literal `anonymous` occupies the space where a reader looks
for attribution and answers nothing. Rule 2 governs only the `finder`
row — a tool that made the discovery is still credited `type: "tool"`.

Wires the policy into the two skills that actually write the field
(`security-issue-import` at intake, `security-issue-sync` at
reconciliation) and cross-references it from `bot-credits-policy.md`.
`security-cve-allocate` and `security-issue-deduplicate` are named in
the policy's own applies-to list but not edited here — neither writes
`credits[]` directly.

Generated-by: Claude Code (Claude Opus 5)
@potiuk potiuk added family:security security-* skills capability:intake Import external signal + sync tracker state labels Aug 29, 2026
@potiuk
potiuk merged commit 31176a4 into apache:main Aug 29, 2026
10 checks passed
potiuk added a commit that referenced this pull request Aug 29, 2026
…anonymous (#1131)

Reconciles #1124 with #1127, as promised in #1127's description.

#1124 made `anonymous` the fallback for a scanner-sourced finding whose
scanner declares no public credit name. #1127 then landed the
finder-credit policy, whose Rule 2 says the opposite: where there is no
named finder, omit the `finder` credit rather than writing a
placeholder. Both are on `main`, so the framework currently contradicts
itself in three places.

Rule 2 wins. It is grounded in an ASF CVE reviewer's feedback on a
published batch — "I'm not sure how helpful it is to credit 'anonymous'
as finder, just leave it out" — and a `credits[]` carrying only the
remediation developer is a complete record, whereas a literal
`anonymous` occupies the space a reader scans for attribution and
answers nothing.

Nothing else about #1124 changes: the scanner's public credit name is
still written when declared, still emitted with `type: "tool"`, and the
confidential product token still never reaches a public surface. Only
the no-name-declared branch changes, from writing a placeholder to
omitting the row.

Grep confirms no `anonymous` fallback remains under skills/, projects/,
or tools/.

Generated-by: Claude Code (Claude Opus 5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

capability:intake Import external signal + sync tracker state family:security security-* skills

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant