From 64ef2b5c06c28da9ef91bdbcfb3ebf6bfb85c5b3 Mon Sep 17 00:00:00 2001 From: Anurag Singh Date: Fri, 30 Oct 2026 06:04:07 +0530 Subject: [PATCH 1/4] refactor(archive): add a generic advisory thread URL template Why: the advisory-URL step built its link from the PonyMail-only ponymail_thread_url_template, so a project on another archive had no template to use. Declare advisory_thread_url_template in the archive system, keep the ASF value as the default, and document the override. --- organizations/ASF/organization.md | 1 + plugins/magpie-setup/templates/project.md | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/organizations/ASF/organization.md b/organizations/ASF/organization.md index 16e65c4e2..a6028e330 100644 --- a/organizations/ASF/organization.md +++ b/organizations/ASF/organization.md @@ -153,6 +153,7 @@ archive_system: list_domain: .apache.org search_url_template: "https://lists.apache.org/list?{list}:{year}-{month}:{query}" api_query_url_template: "https://lists.apache.org/api/thread.lua?list={list}&domain={list_domain}&id={thread_id}" + advisory_thread_url_template: "https://lists.apache.org/thread/{thread_id}?{list}" advisory_publication_signal_url: "https://lists.apache.org/list.html?" # Resolves the placeholder used in agnostic skills: mail_archive_url: https://lists.apache.org diff --git a/plugins/magpie-setup/templates/project.md b/plugins/magpie-setup/templates/project.md index 3a44ff315..183c7e9e3 100644 --- a/plugins/magpie-setup/templates/project.md +++ b/plugins/magpie-setup/templates/project.md @@ -431,6 +431,12 @@ reads mail from a different backend than its organization. Org-level — inherited from your organization's `archive_system` block (public-archive backend + URL templates). Override here only if this project's advisories surface on a different archive than its organization. +The block carries `search_url_template` (query a list for a CVE ID), +`api_query_url_template`, `advisory_thread_url_template` (build the public +advisory URL from a thread id), `advisory_publication_signal_url` and +`mail_archive_url`. The issue-sync advisory step reads +`advisory_thread_url_template`; a project that still declares only the +legacy `ponymail_thread_url_template` keeps working through that key. ### Project metadata From b6e293e73fbbcb11f962012dc4fff0f0e1081cf2 Mon Sep 17 00:00:00 2001 From: Anurag Singh Date: Fri, 30 Oct 2026 06:04:31 +0530 Subject: [PATCH 2/4] docs(issue-sync): look up advisory URLs through the configured archive Why: the step told every project to use the PonyMail MCP or HTTP API, so an adopter on another archive could not find its published advisory. Keep the PonyMail recipe as the ASF default and add the archive-agnostic path through search_url_template and advisory_thread_url_template, falling back to the legacy PonyMail template when that is all the project declares. --- .../skills/issue-sync/signals-to-actions.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/plugins/magpie-security/skills/issue-sync/signals-to-actions.md b/plugins/magpie-security/skills/issue-sync/signals-to-actions.md index 618ccf18b..e45bab087 100644 --- a/plugins/magpie-security/skills/issue-sync/signals-to-actions.md +++ b/plugins/magpie-security/skills/issue-sync/signals-to-actions.md @@ -303,9 +303,9 @@ Group them by category: Empty until Step 13 — the release manager fills it in **after** the advisory email has been sent and archived. Every sync run must: - 1. If `announced - emails sent` is set and the field is still empty, **scan the public users@ archive for the CVE ID**, by one of two paths: + 1. If `announced - emails sent` is set and the field is still empty, **scan the public advisory archive for the CVE ID**, using the archive the project declares in [`/project.md`](../../../..//project.md#archive-system) (`archive_system`): - - **PonyMail MCP (preferred when enabled).** If Step 0 + - **PonyMail, the ASF default (`archive_system.kind: ponymail`).** If Step 0 recorded `ponymail_authenticated: true`, call: ```text @@ -318,19 +318,18 @@ Group them by category: ``` `users@` is public, so no LDAP allowlist check is needed. - A single hit is the advisory thread; capture its `tid` and build the archive URL with the manifest's `ponymail_thread_url_template`. Call shape: [`tools/ponymail/operations.md` — Find the advisory archive thread](../../../../tools/ponymail/operations.md#find-the-advisory-archive-thread-on-usersprojectapacheorg). - - - **PonyMail HTTP API (fallback).** When PonyMail MCP is disabled, unauthenticated, or errors, - use the anonymous-HTTPS HTTP API + `list.html` pattern in + When PonyMail MCP is disabled, unauthenticated, or errors, use the anonymous-HTTPS HTTP API + `list.html` pattern in [`tools/gmail/ponymail-archive.md`](../../../../tools/gmail/ponymail-archive.md#use-case--security-issue-sync); it works for every triager regardless of LDAP status. - URL templates (`ponymail_api_url_template`, `ponymail_public_search_url_template`, `ponymail_thread_url_template`) are in - [`/project.md`](../../../..//project.md#gmail-and-ponymail). + + - **Any other archive (`archive_system.kind` not `ponymail`).** Query the project's `search_url_template` with the CVE ID, open the hit's thread, and take its id. When the archive declares no `search_url_template`, or no hit resolves, ask the release manager for the archived advisory URL instead of guessing. + + A single hit is the advisory thread. Build the public advisory URL with the manifest's `advisory_thread_url_template` (or the legacy `ponymail_thread_url_template` when the project declares only that key). **A search hit is a candidate, not the advisory.** The search matches any public post that mentions the CVE ID (a user question, a reply, a forward), and capturing this URL is what moves the CVE record to `PUBLIC`. - For each hit, fetch the thread (`mcp__ponymail__get_thread`, or the HTTP API) for its list, root subject and root sender, + For each hit, fetch the thread (`mcp__ponymail__get_thread`, the HTTP API, or the archive's own thread page) for its list, root subject and root sender, write `{cve_id, url, thread: {list, subject, from}, advisory_list: , mail_archive_url, authorized_senders}` to a file and run `security-management issue-sync advisory-archive --input `; `authorized_senders` is every release-manager and security-team address from [`/release-trains.md`](../../../..//release-trains.md). @@ -341,7 +340,7 @@ Group them by category: and say that the sender comes from the archived `From:` header and is not cryptographically verified, so the user should recognise the announcement itself before confirming; record it — and run the close-out that follows from it — only once the user explicitly confirms that URL. - On that confirmation, populate the field with the thread URL (per `ponymail_thread_url_template`), + On that confirmation, populate the field with the thread URL (per `advisory_thread_url_template`), regenerate the CVE JSON attachment, and add the `announced` label. 2. If the field is already populated, treat it as authoritative — no scan. Regenerate the CVE JSON attachment so the URL flows into `references[]` as `vendor-advisory`. From ee1efa22195fc1969ec549d8bcf3a92b025b9093 Mon Sep 17 00:00:00 2001 From: Anurag Singh Date: Fri, 30 Oct 2026 11:50:55 +0530 Subject: [PATCH 3/4] docs(setup): align advisory thread template placeholders Why: the ASF organization declares advisory_thread_url_template with {thread_id} and {list}, but the setup template still documented the legacy PonyMail key with the older spelling, and the quick-reference table listed only the legacy key, so adopters reading the table never saw the generic one. Generated-by: OpenCode (DeepSeek V4.1 Flash) --- plugins/magpie-setup/templates/project.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/magpie-setup/templates/project.md b/plugins/magpie-setup/templates/project.md index 183c7e9e3..2ba5794e6 100644 --- a/plugins/magpie-setup/templates/project.md +++ b/plugins/magpie-setup/templates/project.md @@ -304,7 +304,8 @@ remove the row. | `ponymail_private_search_url_template` | `ponymail` | TODO | | `ponymail_public_search_url_template` | `ponymail` | TODO | | `ponymail_api_url_template` | `ponymail` | TODO | -| `ponymail_thread_url_template` | `ponymail` | `https://lists.apache.org/thread/?` | +| `ponymail_thread_url_template` | `ponymail` | `https://lists.apache.org/thread/{thread_id}?{list}` | +| `advisory_thread_url_template` | `archive_system` (org) | `https://lists.apache.org/thread/{thread_id}?{list}` | | `imap_host` | `imap` | TODO: e.g. `imap.example.org` | | `imap_account` | `imap` | TODO: e.g. `security-triage@example.org` | | `imap_security_list_folder` | `imap` | TODO: e.g. `INBOX.security-list` | From eb6a22fcf25b04cea6e24b47f8116e28e971cc38 Mon Sep 17 00:00:00 2001 From: Jarek Potiuk Date: Fri, 30 Oct 2026 19:12:58 +0100 Subject: [PATCH 4/4] fix(archive): spell the advisory permalink's full list address In the same archive_system block, {list} is the list's local part (api_query_url_template pairs it with {list_domain}), so ?{list} would have rendered ?users instead of the full-address permalink trackers store and the CVE record publishes. Spell ?{list}@{list_domain} in the ASF organization and the project template. Tell issue-sync what to do when neither URL template is declared (use the archive's permalink or ask the release manager), and keep the legacy key in the confirmation step consistent with the lookup step. Generated-by: Claude Opus 5 --- organizations/ASF/organization.md | 2 +- .../magpie-security/skills/issue-sync/signals-to-actions.md | 3 ++- plugins/magpie-setup/templates/project.md | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/organizations/ASF/organization.md b/organizations/ASF/organization.md index a6028e330..97aa74469 100644 --- a/organizations/ASF/organization.md +++ b/organizations/ASF/organization.md @@ -153,7 +153,7 @@ archive_system: list_domain: .apache.org search_url_template: "https://lists.apache.org/list?{list}:{year}-{month}:{query}" api_query_url_template: "https://lists.apache.org/api/thread.lua?list={list}&domain={list_domain}&id={thread_id}" - advisory_thread_url_template: "https://lists.apache.org/thread/{thread_id}?{list}" + advisory_thread_url_template: "https://lists.apache.org/thread/{thread_id}?{list}@{list_domain}" advisory_publication_signal_url: "https://lists.apache.org/list.html?" # Resolves the placeholder used in agnostic skills: mail_archive_url: https://lists.apache.org diff --git a/plugins/magpie-security/skills/issue-sync/signals-to-actions.md b/plugins/magpie-security/skills/issue-sync/signals-to-actions.md index e45bab087..39c433edc 100644 --- a/plugins/magpie-security/skills/issue-sync/signals-to-actions.md +++ b/plugins/magpie-security/skills/issue-sync/signals-to-actions.md @@ -326,6 +326,7 @@ Group them by category: - **Any other archive (`archive_system.kind` not `ponymail`).** Query the project's `search_url_template` with the CVE ID, open the hit's thread, and take its id. When the archive declares no `search_url_template`, or no hit resolves, ask the release manager for the archived advisory URL instead of guessing. A single hit is the advisory thread. Build the public advisory URL with the manifest's `advisory_thread_url_template` (or the legacy `ponymail_thread_url_template` when the project declares only that key). + When neither key is declared, use the thread permalink the archive returned, or ask the release manager; never construct one. **A search hit is a candidate, not the advisory.** The search matches any public post that mentions the CVE ID (a user question, a reply, a forward), and capturing this URL is what moves the CVE record to `PUBLIC`. @@ -340,7 +341,7 @@ Group them by category: and say that the sender comes from the archived `From:` header and is not cryptographically verified, so the user should recognise the announcement itself before confirming; record it — and run the close-out that follows from it — only once the user explicitly confirms that URL. - On that confirmation, populate the field with the thread URL (per `advisory_thread_url_template`), + On that confirmation, populate the field with the thread URL (per `advisory_thread_url_template`, or the legacy `ponymail_thread_url_template`), regenerate the CVE JSON attachment, and add the `announced` label. 2. If the field is already populated, treat it as authoritative — no scan. Regenerate the CVE JSON attachment so the URL flows into `references[]` as `vendor-advisory`. diff --git a/plugins/magpie-setup/templates/project.md b/plugins/magpie-setup/templates/project.md index 2ba5794e6..d41aeb4c7 100644 --- a/plugins/magpie-setup/templates/project.md +++ b/plugins/magpie-setup/templates/project.md @@ -304,8 +304,8 @@ remove the row. | `ponymail_private_search_url_template` | `ponymail` | TODO | | `ponymail_public_search_url_template` | `ponymail` | TODO | | `ponymail_api_url_template` | `ponymail` | TODO | -| `ponymail_thread_url_template` | `ponymail` | `https://lists.apache.org/thread/{thread_id}?{list}` | -| `advisory_thread_url_template` | `archive_system` (org) | `https://lists.apache.org/thread/{thread_id}?{list}` | +| `ponymail_thread_url_template` | `ponymail` | `https://lists.apache.org/thread/{thread_id}?{list}@{list_domain}` | +| `advisory_thread_url_template` | `archive_system` (org) | `https://lists.apache.org/thread/{thread_id}?{list}@{list_domain}` | | `imap_host` | `imap` | TODO: e.g. `imap.example.org` | | `imap_account` | `imap` | TODO: e.g. `security-triage@example.org` | | `imap_security_list_folder` | `imap` | TODO: e.g. `INBOX.security-list` |