This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow-steward.git
The following commit(s) were added to refs/heads/main by this push:
new e40b093 import: consolidated receipt + Report (disposition converged)
sub-class (#152)
e40b093 is described below
commit e40b093036295fe9380b01de822c43e8b6cbd303
Author: Jarek Potiuk <[email protected]>
AuthorDate: Thu May 14 13:05:02 2026 +0200
import: consolidated receipt + Report (disposition converged) sub-class
(#152)
Two related improvements to security-issue-import:
1. Consolidated receipt pattern (Step 5)
When N>1 trackers are imported from the same reporter or same
source thread within one skill run, propose a single
consolidated receipt-of-confirmation reply listing all N
tracker URLs, instead of N redundant receipts. Reporters get
one credit-preference question, not N.
Detection: same threadId in tracker provenance / same From:
address / shared outer thread.
2. Report (disposition converged) sub-class (Step 3)
New classification row detected when the inbound thread
already has a team-member substantive technical disposition
AND the reporter has acknowledged it before the tracker was
created. The tracker is still created (audit trail) but the
canned receipt is skipped (it would be tone-deaf) and the
rollup entry notes the converged state.
Step 7 step 4 (draft creation) updated to skip both cases
correctly with explicit cross-linking in the rollup entry.
Motivation: both patterns surfaced in the 2026-05-14 import
sweep against airflow-s/airflow-s:
- Lokhesh Ujhoodha's 4 split-out GHSAs were correctly imported
but the existing per-tracker receipt pattern would have sent
him 4 redundant emails asking the credit-preference question
4 times. We sent a single consolidated reply manually.
- airflow-s#408 (edge3 worker JWT) had Omkhar Arasaratnam's
Option-1-or-Option-2 disposition already agreed with Jarek
on the inbound thread, with the docs PR already open. The
canned receipt would have been tone-deaf. We skipped the
draft manually.
Codifying both patterns prevents the next operator from having
to detect and handle these cases by hand.
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
---
.claude/skills/security-issue-import/SKILL.md | 59 ++++++++++++++++++++++++++-
1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/.claude/skills/security-issue-import/SKILL.md
b/.claude/skills/security-issue-import/SKILL.md
index 9bbadba..5b58eb4 100644
--- a/.claude/skills/security-issue-import/SKILL.md
+++ b/.claude/skills/security-issue-import/SKILL.md
@@ -734,6 +734,7 @@ Decide the candidate's class from the root message:
|---|---|---|
| **Report**: a reporter describes a vulnerability | The body has a
description, a PoC / reproduction steps, an impact claim. Sender is an external
address (not `@apache.org`, not on the security-team roster in
[`AGENTS.md`](../../../AGENTS.md)). | Proceed to Step 4. |
| **ASF-security relay**: `[email protected]` forwarded a report from a
reporter via the Foundation channel | Sender is `[email protected]`. The body
almost always starts with the ASF forwarding preamble — *"Dear PMC, The
security vulnerability report has been received by the Apache Security Team and
is being passed to you for action …"* — and contains the original report
underneath (often after a `====GHSA-…` separator when the report came in via
GitHub Security Advisory). The pream [...]
+| **Report (disposition converged)**: a `Report` where the inbound thread has
a team-member substantive technical disposition AND the reporter has
acknowledged it | Same body shape as `Report`, but the thread has a team-member
reply with one of: option-1/option-2 framing, *"we agree, opening fix PR"*
disposition, a docs-clarification acknowledgement; AND the reporter has replied
confirming the disposition; AND no further reporter follow-up is needed.
Detected at Step 3 by reading the thr [...]
| **CVE-tool bookkeeping**: an automated or human status-change notification
on the ASF CVE tool | Sender is `[email protected]` (or one of the
security-team members acting on behalf of the CVE tool). Subject matches one
of: `"CVE-YYYY-NNNNN reserved for airflow"`, `"Comment added on
CVE-YYYY-NNNNN"`, `"CVE-YYYY-NNNNN is now READY"`, `"CVE-YYYY-NNNNN is now
PUBLIC"`, `"CVE-YYYY-NNNNN is now PUBLISHED"`, `"CVE-YYYY-NNNNN REJECTED"`, or
a verbatim `"<state-change>"` line in the body poin [...]
| **Automated scanner dump**: SAST/DAST tool output, CodeQL/Dependabot alert
paste, a string of "issues" with no human PoC | Body is machine-generated,
contains multiple unrelated findings, no explanation of Security Model
violation | Surface as a candidate with class `automated-scanner` and **do
not** propose auto-import. In Step 5 the skill proposes a Gmail draft from the
*"Automated scanning results"* canned response in
[`canned-responses.md`](../../../<project-config>/canned-response [...]
| **Consolidated multi-issue report**: one email bundles ≥3 unrelated
vulnerabilities | The root message has headings like *"Issue 1"*, *"Issue 2"*,
each of which would be its own tracker | Surface class
`consolidated-multi-issue`; do not auto-import. Propose the "Sending multiple
issues in consolidated report" canned reply. |
@@ -845,6 +846,47 @@ Present all candidates as a single numbered proposal
grouped by class:
the user knows the filter is working but is not forced to scroll
past them.
+### Consolidated receipts for multi-tracker imports
+
+When the resolved selector imports **N > 1 trackers from the same
+reporter or same source thread within one skill run**, propose a
+**single consolidated receipt-of-confirmation reply** that lists
+all N tracker URLs, instead of N separate receipts.
+
+**Detection conditions** (any one is sufficient):
+
+1. All N trackers reference the same Gmail `threadId` in their
+ "Split from" / "Imported from" provenance (e.g. one reporter
+ split a consolidated report into N separate GHSAs).
+2. All N trackers' inbound `From:` addresses are identical
+ (same reporter sent N independent reports in the same run).
+3. All N trackers were imported from N distinct threads that
+ *share an outer thread* (one reporter, one root, N
+ sub-threads).
+
+**Consolidated receipt shape**:
+
+- Reply on the **earliest** thread in the set (where the team
+ has an established channel with the reporter — typically the
+ consolidated-pre-split thread).
+- List each tracker URL + GHSA ID / equivalent identifier on
+ its own line, one per tracker.
+- Ask the credit-preference question **once**, applying to all
+ trackers in the set.
+- Use the *"Confirmation of receiving the report"* canned body
+ with a leading paragraph that lists the trackers.
+
+**Skip the per-tracker receipt drafts** when the consolidated
+one is created. Surface the consolidated draft in the proposal
+with explicit *"this reply covers trackers #N1, #N2, …"*
+framing so the user knows what's bundled.
+
+**Coherence check**: the consolidated reply must accurately
+characterise *each* tracker (not just the largest one). If the
+reports differ in subject material to the point where one
+consolidated reply would be confusing, fall back to the
+per-tracker receipt pattern; do not force the bundle.
+
### Canned-response discipline for negative-response drafts
When the proposed disposition is a negative response — any of the
@@ -1118,7 +1160,22 @@ For each confirmed `Report` / `ASF-security relay`:
workflow being correctly configured. The mutation is a no-op when
the item is already on the board with the same Status.
-4. Draft the receipt-of-confirmation reply. **Apply the
+4. Draft the receipt-of-confirmation reply **unless one of**:
+
+ - The candidate class is `Report (disposition converged)` —
+ skip the draft entirely; note the converged disposition in
+ the rollup entry (step 5 below) with the exact prior thread
+ URL / message-id where the disposition was reached. Do not
+ create a Gmail draft for this tracker.
+ - The candidate is part of a **consolidated-receipt bundle**
+ (see Step 5's *"Consolidated receipts for multi-tracker
+ imports"* subsection) — the consolidated draft has already
+ been proposed and confirmed at Step 5; this per-tracker
+ draft is skipped because the bundle covers it. Cross-link
+ the consolidated draft's `<draftId>` in this tracker's
+ rollup entry.
+
+ When a draft is created (the default path), **apply the
reveal-before-send protocol if (and only if) the rendered
draft body carries any third-party identifiers** (per the
Step 4 redact-after-fetch above; the receipt template