TODO:

June 2, 2026 · View on GitHub

This is the project configuration for TODO: <project-name>. Every skill under ../../.claude/skills/ reads the project name from <project-config>/project.md and then loads this manifest to resolve project-specific identity, repositories, mailing lists, and references to the other files in this directory.

Grep for TODO to see every field you still need to fill in:

grep -n TODO projects/<name>/project.md

Identity

KeyValue
project_nameTODO: e.g. Apache Foo
vendorTODO: e.g. Apache Software Foundation
short_nameTODO: e.g. Foo
product_family_urlTODO: e.g. https://foo.apache.org/

The vendor / project_name pair is what lands in the vendor and product fields of the CVE 5.x record the CVE-JSON generator produces.

Repositories

KeyValuePurpose
tracker_repoTODO: e.g. foo-s/foo-sPrivate security tracker (this repo)
tracker_repo_urlTODO
tracker_default_branchTODO: e.g. mainDefault PR target for the tracker repo
tracker_project_board_urlTODO: URL of the GitHub Project V2 board, if anySecurity board
upstream_repoTODO: e.g. apache/fooPublic codebase where fixes land
upstream_repo_urlTODO
upstream_default_branchTODO: e.g. master (older default) or mainUpstream's default branch — what <default-branch> resolves to. Distinct from tracker_default_branch (the security tracker repo's PR target)
upstream_agents_md_urlTODO: https://github.com/<upstream>/blob/main/AGENTS.mdConventions this repo mirrors
upstream_contributing_docs_urlTODO
upstream_genai_disclosure_anchorTODO: URL + anchor for the project's Gen-AI disclosure guideline
upstream_security_policy_urlTODO: https://github.com/<upstream>/security/policy

Mailing lists

KeyValueNotes
security_listTODO: e.g. security@foo.apache.orgInbound reports; not publicly archived
private_listTODO: e.g. private@foo.apache.orgPMC escalation; not publicly archived
users_listTODO: e.g. users@foo.apache.orgPublic advisories end up here; publicly archived
dev_listTODO: e.g. dev@foo.apache.orgRelease [RESULT][VOTE] threads; publicly archived
announce_listTODO: e.g. announce@apache.orgCross-project announcement list; publicly archived
commits_listTODO: e.g. commits@foo.apache.orgPublicly archived
asf_security_listsecurity@apache.orgASF-wide security team; relays some inbound reports

Public archives typically live at https://lists.apache.org/list.html?<list>. Private lists on lists.apache.org/thread/<id> 404 for non-members. Only URLs on publicly archived lists may appear in CVE references[] as vendor-advisory; see ../../AGENTS.md and security-model.md.

Tools enabled

CapabilityToolAdapter directoryConfig knobs declared here
Issue tracking + source control + project boardgithub../../tools/github/tracker_repo, upstream_repo, github_project_board_*, issue_template_fields
Inbound email / drafts<one or more mail-source backends>../../tools/mail-source/contract.md (abstract) + per-backend adapter dirs (tools/gmail/, tools/ponymail/, tools/mail-source/imap/, tools/mail-source/mbox/, ...)See Mail sources below — declare each backend's role (primary / preferred-for-<op> / fallback / optional) and mandatory flag
CVE allocation + record mgmtvulnogram../../tools/cve-tool-vulnogram/see CVE tooling below
ASF project metadata (rosters / people / releases)apache-projects../../tools/apache-projects/see project_metadata below — ASF default mandatory: true
Release voting / announceTODO: ASF mailing lists — or replace with the project's release-comms backendvia dev_list / announce_list / users_list

To replace a tool (e.g. swap GitHub issues for JIRA), declare an alternate tool in the table above, add a tools/<name>/ adapter directory, and make sure the values the generic skills need are still reachable from this manifest.

CVE tooling

TODO: describe which CNA tool the project uses. For ASF projects the default is ASF's Vulnogram; other CNAs will substitute their own equivalents. The Vulnogram-side mechanics live under ../../tools/cve-tool-vulnogram/; the per-project values below are what the generic recipes substitute in.

KeyValue
cve_toolTODO: e.g. vulnogram (ASF-hosted)
cve_tool_allocate_urlTODO: e.g. https://cveprocess.apache.org/allocatecve
cve_tool_record_url_templateTODO: e.g. https://cveprocess.apache.org/cve5/<CVE-ID>
cve_tool_source_tab_url_templateTODO
cve_allocation_gated_byTODO: e.g. Foo PMC membership (ASF OAuth)
asf_org_idTODO: project's CNA org UUID (for ASF projects: f0158376-9dc2-43b6-827c-5f631a4d8d09)
cna_private_ownerTODO: e.g. foo (CNA_private.owner — identifies the project slug inside the ASF CNA queue)
cna_private_projecturlTODO: e.g. https://foo.apache.org/
cna_private_userslistTODO: e.g. users@foo.apache.org

GitHub project board

If the project uses a Projects V2 board for its security-issue view, declare the node IDs below. Fetch with the introspection query in ../../tools/github/project-board.md. If the project does not run a board, leave the table blank — skills treat missing board config as "no board reconciliation".

KeyValue
project_board_urlTODO
project_board_numberTODO
project_board_node_idTODO
status_field_node_idTODO

Status column → option-ID mapping (re-fetch if any write returns not found):

ColumnOption ID
Needs triageTODO
AssessedTODO
CVE allocatedTODO
PR createdTODO
PR mergedTODO
Fix releasedTODO
AnnouncedTODO

Mail sources

The skills treat every supported mail backend the same way — through the abstract operations defined in ../../tools/mail-source/contract.md. The adopter declares which backends are configured, what role each plays, and whether any are mandatory. The skill's resolution rule (see the contract) then picks the right backend per operation at run time.

Backend declaration

One row per configured backend. Exactly one row carries role: primary. Multiple rows may carry preferred for <op> to override the primary for specific operations. fallback rows are tried in order when no preferred / primary backend supports the op. mandatory: yes means the skill refuses to run when that backend is unavailable; no means the skill continues with the remaining backends (and skips ops that no available backend supports).

BackendRoleMandatoryNotes
TODO: gmailTODO: e.g. primaryTODO: yes / noTODO: e.g. "Triager Gmail account subscribed to <security-list> and <private-list>"
TODO: ponymailTODO: e.g. fallback or preferred for thread_urlTODO: ASF default yesTODO: e.g. "Read-only archive backstop; PMC LDAP session required for private-list reads"
TODO: (add more rows as needed — imap, mbox, project-specific adapter)

ASF default — ponymail is mandatory: yes. For ASF projects the PonyMail MCP is a pre-flight prerequisite, not an opt-in backstop: the mail-reading skills that run the Step 0 mail-source check (security-issue-import, security-issue-sync) refuse to run when it is unavailable, even though gmail keeps the primary role (PonyMail is read-only — drafts stay on Gmail). Skills that only touch a single Gmail thread opportunistically (e.g. security-cve-allocate) do not hard-gate on it. Install it from the latest main of apache/comdev per ../../tools/ponymail/tool.md. A non-ASF adopter with no lists.apache.org archive sets this row to mandatory: no (or drops it).

Reference adapter docs: tools/gmail/tool.md (full read+write), tools/ponymail/tool.md (read-only ASF archive), tools/mail-source/imap/README.md (stub), tools/mail-source/mbox/README.md (read-only offline archive — stub).

Per-backend config

Per-backend values the generic recipes substitute in. Only fill in the rows for backends declared above; leave the rest blank or remove the row.

KeyBackendValue
security_list_domaingmailTODO: e.g. security.foo.apache.org — Gmail list: operator uses the domain form
ponymail_private_search_url_templateponymailTODO
ponymail_public_search_url_templateponymailTODO
ponymail_api_url_templateponymailTODO
ponymail_thread_url_templateponymailhttps://lists.apache.org/thread/<hash>?<list>
imap_hostimapTODO: e.g. imap.example.org
imap_accountimapTODO: e.g. security-triage@example.org
imap_security_list_folderimapTODO: e.g. INBOX.security-list
imap_drafts_folderimapTODO: e.g. Drafts (or leave blank to declare create_draft unsupported on this adapter)
mbox_archive_pathmboxTODO: e.g. /srv/audit/security-list-2024.mbox

Issue-template fields

The skills' body-field roles map to the following concrete ### headings in the project's issue template (the concrete YAML file lives in the adopter's <upstream> repo; the generic role → field contract is in The generic role → GitHub-field contract lives in ../../tools/github/issue-template.md; the concrete names below are what skills read and write for this project.

Role (generic)Field nameTemplate typeRequired?
issue-descriptionTODOtextareaTODO
public-summaryTODOtextareaTODO
affected-versionsTODOinputTODO
security-threadTODOinputTODO
public-advisory-urlTODOinputTODO
reporter-creditTODOinputTODO
pr-with-fixTODOinputTODO
cweTODOinputTODO
severityTODOdropdownTODO
cve-tool-linkTODOinputTODO

Security workflow configuration

This block declares the plug-points that drive every ASF-coupled assumption in the skills. The defaults shipped here reproduce the current Apache Airflow security-team behaviour byte-for-byte: an adopter who copies projects/_template/ into a fresh <project-config>/ and changes nothing in this section ends up with the same workflow that runs in airflow-s/airflow-s today. Non-ASF adopters override individual fields (CNA tool, mail backend, archive system, governance gate, etc.) without touching skill bodies — skills resolve these knobs at run time. Each field carries a # comment stating what it controls, the ASF default, when a non-ASF adopter would override it, and the consuming skills (1-3 most relevant names).

The adapter contracts these blocks reference live under:

CVE authority

cve_authority:
  # Which CNA tool the project uses to allocate, edit, and publish CVE
  # records. Selects the adapter under tools/cve-tool/.
  # ASF default: vulnogram (ASF-hosted Vulnogram instance at
  # cveprocess.apache.org). Non-ASF adopters running their own MITRE
  # CNA pick `mitre-form` or `cve-org-direct`; GHSA-only projects pick
  # `ghsa`; pre-CNA projects pick `none`.
  # Consumed by: security-cve-allocate, security-issue-sync,
  # generate-cve-json.
  tool: vulnogram

  # Front-door allocation URL. Skill prints this and waits for the
  # operator to paste the allocated ID back.
  # ASF default: Vulnogram's ASF allocation endpoint.
  # Override when: pointing at a non-ASF Vulnogram tenant, or any
  # other CNA tool's allocation UI.
  # Consumed by: security-cve-allocate.
  allocate_url: https://cveprocess.apache.org/allocatecve

  # Template for the per-record edit/view URL. `<CVE-ID>` is the
  # placeholder the skill substitutes.
  # ASF default: Vulnogram's cve5 record view.
  # Override when: any non-Vulnogram CNA tool.
  # Consumed by: security-cve-allocate, security-issue-sync.
  record_url_template: https://cveprocess.apache.org/cve5/<CVE-ID>

  # Template for the "Source" tab inside the CNA tool — used when the
  # skill needs to inspect raw CNA_private state.
  # ASF default: Vulnogram cve5 source tab.
  # Override when: the adapter exposes raw record state via a
  # different URL (or leave null if the adapter has no equivalent).
  # Consumed by: security-issue-sync, generate-cve-json.
  source_tab_url_template: https://cveprocess.apache.org/cve5/<CVE-ID>?tab=source

  # Template for the "preview the allocation email" tab in the CNA
  # tool. The Vulnogram default emits an allocation email visible
  # under this URL; null for adapters that don't preview email.
  # ASF default: Vulnogram email preview tab.
  # Consumed by: security-cve-allocate.
  email_preview_url_template: https://cveprocess.apache.org/cve5/<CVE-ID>?tab=email

  # Generic state machine the adapter exposes. Adapters map their
  # tool-native states to this 4-stop sequence; the rest of the
  # workflow speaks only in these terms.
  # ASF default mapping: Vulnogram's DRAFT -> allocated,
  # REVIEW -> review-ready, READY -> publish-ready, PUBLIC -> public.
  # Override when: the adapter has a different state machine — the
  # adapter declares its own mapping in its README.md.
  # Consumed by: security-issue-sync, security-cve-allocate,
  # generate-cve-json.
  states: [allocated, review-ready, publish-ready, public]

  # How "record is now PUBLIC" propagates back to the workflow.
  # `poll` = skill re-fetches the record on a sweep; `webhook` =
  # adapter pushes; `manual` = operator flips a label by hand.
  # ASF default: poll (Vulnogram has no webhook).
  # Override when: a CNA tool offers a webhook (`webhook`) or only a
  # human-driven publication signal (`manual`).
  # Consumed by: security-issue-sync.
  publication_propagation: poll

  # Whether the CNA tool emits an allocation email of its own that
  # the skills should expect to see on the security mailing list.
  # ASF default: true (Vulnogram auto-emails the assigner list).
  # Override when: the adapter is silent on allocation — skills then
  # skip the "wait for Vulnogram email" step.
  # Consumed by: security-cve-allocate.
  emits_allocation_email: true

  # Where the human review of the draft CVE record happens before
  # publication. `mailing-list` = an off-system thread; `github-pr`
  # = a PR on the tracker repo; `none` = no formal review gate.
  # ASF default: mailing-list (PMC reviews on private@).
  # Override when: an adopter wires review into a tracker-repo PR.
  # Consumed by: security-cve-allocate, security-issue-sync.
  reviewer_channel: mailing-list

Governance

governance:
  # Who has authority to allocate a CVE on behalf of the project.
  # `pmc-member` = an ASF-style governance committee membership gate;
  # `security-team-member` = looser, anyone on the security team;
  # `maintainer` = any committer; `none` = no formal gate.
  # ASF default: pmc-member (ASF PMC membership via OAuth into
  # Vulnogram).
  # Override when: non-ASF projects with their own authority model.
  # Consumed by: security-cve-allocate, security-issue-sync.
  cve_allocation_gate: pmc-member

  # Label the tracker applies to mark "this account is governance-
  # authorised" — distinct from "security-team member". Skills use
  # this to gate the allocation step.
  # ASF default: "PMC" (matches the existing airflow-s label).
  # Override when: a non-ASF adopter uses a different label name.
  # Consumed by: security-cve-allocate, pr-management-triage.
  gate_label: "PMC"

  # Whether release votes block on outstanding security work. When
  # true, release-manager skills check the security tracker for
  # un-fixed-but-public CVEs before greenlighting a vote.
  # ASF default: true (ASF release process gates on this).
  # Override when: projects with no formal release-vote gate.
  # Consumed by: security-issue-sync, generate-cve-json.
  release_vote_gating: true

  # Private mailing list the governance body uses for escalation,
  # PMC discussions, and "this is bigger than security@" routing.
  # ASF default: private@<project>.apache.org.
  # Override when: non-ASF — point at the equivalent private list
  # or leave null if no such list exists.
  # Consumed by: security-issue-sync, security-issue-invalidate.
  private_governance_list: private@<project>.apache.org

  # GitHub handle (or external contact) the skills cc / @-mention
  # when escalating beyond the security team.
  # ASF default: the PMC chair or designated escalation contact —
  # filled in per-project. Use the `@<handle>` form for GitHub
  # surfaces; an email is acceptable for off-GitHub escalation.
  # Override when: non-ASF — point at the equivalent role-holder.
  # Consumed by: security-issue-sync, pr-management-triage.
  escalation_contact: "@<escalation-contact>"

  # URL of the public committee roster, used for "is this person
  # authorised" checks in the allocation flow.
  # ASF default: ASF committee URL (whimsy/projects/.../committee).
  # Override when: non-ASF — link to the equivalent roster page.
  # Consumed by: security-cve-allocate.
  roster_url: https://projects.apache.org/committee.html?<project>

Security inbox

security_inbox:
  # The inbound channel reports land on. `mailing-list` = an SMTP
  # address; `ghsa-inbox` = GitHub Security Advisories private
  # reports; `hackerone` = a HackerOne program inbox;
  # `chat-channel` = e.g. a private Slack; `intake-form` = a
  # web form posting into a tracker.
  # ASF default: mailing-list.
  # Override when: non-ASF projects on GHSA / HackerOne / etc.
  # Consumed by: security-issue-import, security-issue-sync.
  kind: mailing-list

  # The concrete address / channel ID / form URL the inbound channel
  # uses. For `mailing-list`, this is the SMTP address.
  # ASF default: security@<project>.apache.org.
  # Override when: non-ASF — replace with the adopter's inbox.
  # Consumed by: security-issue-import, security-issue-sync,
  # canned-responses templating.
  address: <security-list>

  # The foundation-wide security address that gates the
  # "don't exclude this sender" rule in the inbound importer.
  # Null for non-ASF adopters with no foundation-level inbox.
  # ASF default: security@apache.org (the ASF security team
  # forwards reports here onto project security@ lists).
  # Override when: non-ASF — set to null (or your foundation's
  # equivalent address if one exists).
  # Consumed by: security-issue-import.
  foundation_security_address: security@apache.org

  # Whether reports arrive via a forwarder/relay (an upstream party
  # that triages and re-sends, rather than the reporter mailing the
  # project list directly). When true, the forwarders block below
  # declares the enabled adapters.
  # ASF default: true (the ASF security team relays many reports).
  # Override when: non-ASF projects with no forwarder layer.
  # Consumed by: security-issue-import, gmail/asf-relay (adapter).
  has_forwarder_relay: true

  # Optional Gmail/IMAP search filter used by the inbound importer to
  # scope which threads count as "security inbox messages".
  # ASF default: `list:<security-list-domain>` (Gmail's list-id
  # filter for the project security list).
  # Override when: the mail backend uses a different scoping
  # mechanism (folder, label, etc.).
  # Consumed by: security-issue-import.
  list_filter_query: "list:<security-list-domain>"

Forwarders

forwarders:
  # Enabled forwarder/relay adapters. Each name must match an
  # adapter directory under tools/ that conforms to
  # tools/forwarder-relay/README.md.
  # ASF default: [asf-security] — the ASF security team relays
  # reports onto project security@ lists with a known preamble and
  # credit line.
  # Override when: non-ASF — set to [] if no forwarder layer
  # exists, or add the adopter's relay adapter name(s) here.
  # Consumed by: security-issue-import, gmail/asf-relay (adapter).
  enabled: [asf-security]

  # Per-adapter configuration. Keys must match `enabled` entries.
  asf-security:
    # Handle / address the forwarder sends from. Skills use this to
    # detect "this is a relayed message, not a direct report".
    # ASF default: security@apache.org.
    # Override when: a different upstream relay address.
    # Consumed by: gmail/asf-relay, security-issue-import.
    contact_handle: security@apache.org

    # Regex matched against the message body to confirm a message
    # really is a relay (not just a CC'd address).
    # ASF default: the ASF preamble — "Dear PMC, The security
    # vulnerability report..."
    # Override when: a different relay's preamble shape.
    # Consumed by: gmail/asf-relay, security-issue-import.
    preamble_match: "^Dear PMC,\\s+The security vulnerability report"

    # Rule the adapter uses to lift the original reporter's credit
    # line out of the relayed body. Adapters define their own
    # extraction shape; see tools/forwarder-relay/README.md.
    # ASF default: the existing ASF-security credit extraction (the
    # "Reported by: <name> <<email>>" line near the top of the
    # forwarded body).
    # Override when: a different relay shape.
    # Consumed by: gmail/asf-relay, security-issue-import.
    credit_extraction_rule: "first-line-matching:^Reported by:\\s+(.+)$"

Mail provider

mail_provider:
  # Primary mail backend the skills read inbound mail from and write
  # drafts into. Adapters live under tools/<backend>/.
  # ASF default: gmail-mcp (triager Gmail account via the Gmail MCP
  # adapter at tools/gmail/).
  # Override when: a non-ASF adopter uses an IMAP triager mailbox
  # (`imap`), an Outlook inbox (`outlook`), or a forum-style
  # inbound channel (`discourse`).
  # Consumed by: security-issue-import, security-issue-sync,
  # security-issue-invalidate (draft replies).
  primary: gmail-mcp

  # Read-only fallback backend used when the primary can't reach a
  # thread (e.g. message older than the Gmail retention window).
  # `none` means no fallback — operations that fail on the primary
  # surface a hard error instead of trying a secondary.
  # ASF default: ponymail (read-only ASF archive backstop).
  # Override when: non-ASF adopters typically set this to `none`
  # or to their own archive adapter (hyperkitty, mbox, ...).
  # Consumed by: security-issue-sync, security-issue-import.
  fallback: ponymail

Archive system

archive_system:
  # Public mailing-list / forum archive the project's advisories
  # eventually surface on. Adapter selection — drives URL shapes
  # and thread-fetch verbs.
  # ASF default: ponymail (lists.apache.org).
  # Override when: non-ASF adopters on hyperkitty (Mailman 3),
  # discourse, google-groups, github-discussions, or none.
  # Consumed by: security-issue-sync, generate-cve-json.
  kind: ponymail

  # Domain the public lists live under — used to assemble per-list
  # URLs (`<list>@<list_domain>`) when the archive search needs
  # qualified addresses.
  # ASF default: <project>.apache.org (e.g. airflow.apache.org).
  # Override when: non-ASF — the adopter's public-list domain.
  # Consumed by: security-issue-sync, generate-cve-json.
  list_domain: <project>.apache.org

  # Template the search-thread verb assembles. Placeholders:
  # `{list}` (list short name), `{year}`, `{month}`, `{query}`.
  # ASF default: ponymail's `list?` search endpoint.
  # Override when: a different archive's search URL shape.
  # Consumed by: security-issue-sync (search before announce),
  # generate-cve-json (references[] assembly).
  search_url_template: "https://lists.apache.org/list?{list}:{year}-{month}:{query}"

  # Template for the archive's programmatic thread-fetch endpoint
  # (used by the mail-archive adapter's fetch_thread_by_url).
  # ASF default: ponymail's thread.lua API.
  # Override when: a different archive — hyperkitty has a different
  # API shape; discourse exposes JSON on `/t/<id>.json`; etc.
  # Consumed by: tools/ponymail (adapter), security-issue-sync.
  api_query_url_template: "https://lists.apache.org/api/thread.lua?list={list}&domain={list_domain}&id={thread_id}"

  # The URL the skill polls to detect "advisory has been announced
  # publicly" — i.e. the archive page where the announcement thread
  # appears once published.
  # ASF default: lists.apache.org `users` list page.
  # Override when: the announcement surfaces on a different list /
  # forum.
  # Consumed by: security-issue-sync.
  advisory_publication_signal_url: "https://lists.apache.org/list.html?<users-list>"

Project metadata

project_metadata:
  # Backend the skills query for ASF project metadata — committee /
  # committer rosters, people + Apache IDs, employer affiliations,
  # release history. Selects the adapter under tools/.
  # ASF default: apache-projects-mcp (the official comdev MCP at
  # apache/comdev/mcp/apache-projects-mcp, wrapping
  # projects.apache.org/json — read-only, unauthenticated).
  # Override when: non-ASF projects with no projects.apache.org
  # record — set kind to the adopter's governance metadata source,
  # or `none` to supply roster / affiliation context by hand.
  # Consumed by: contributor-nomination, release-vote-tally,
  # the roster-resolution paths in security-issue-sync /
  # security-cve-allocate.
  kind: apache-projects-mcp

  # Whether the metadata backend is a pre-flight prerequisite. When
  # true, the consuming skills refuse to run on degraded signal (the
  # mcp__apache-projects__* tools absent / unreachable) rather than
  # falling back to hand-scraping committer.cgi / committee.html.
  # ASF default: true — for ASF projects the MCP is mandatory.
  # Override when: non-ASF — set false (no ASF project record), and
  # the skills fall back to nominator-supplied roster signal.
  # Consumed by: contributor-nomination, release-vote-tally.
  mandatory: true

  # Install source for the local MCP checkout. The comdev MCP
  # servers ship as in-repo source with no tagged releases, so the
  # framework intentionally tracks `main` rather than pinning — see
  # tools/apache-projects/tool.md → "Keeping the checkout current".
  # ASF default: apache/comdev @ main.
  # Override when: a fork / mirror — point at it, keeping the
  # track-main contract.
  # Consumed by: setup-isolated-setup-verify, setup-isolated-setup-update.
  install_source: "apache/comdev @ main (mcp/apache-projects-mcp)"

Tracker

tracker:
  # Platform the tracker repo lives on. Selects the API adapter
  # (gh CLI today; gitlab CLI / forgejo / jira REST in the future).
  # ASF default: github (airflow-s/airflow-s).
  # Override when: non-ASF adopters on gitlab, gitea, jira, forgejo.
  # Consumed by: every skill that touches the tracker.
  platform: github

  # Project-board backend on the tracker platform. Drives the
  # board-reconciliation step in the triage skills.
  # ASF default: github-projects-v2.
  # Override when: gitlab-board for a GitLab tracker, or `none`
  # if the adopter doesn't run a board at all.
  # Consumed by: pr-management-triage, security-issue-sync,
  # security-issue-triage.
  board: github-projects-v2

  # Visibility of the tracker repo. Drives "may this URL leak
  # publicly" guards in the canned-responses + CVE-JSON references.
  # ASF default: private (tracker existence is itself secret per
  # the AGENTS.md rules).
  # Override when: a project that runs its security tracker openly.
  # Consumed by: every skill that emits URLs to outside surfaces.
  visibility: private

  # Whether the reporter can see the tracker issue once opened.
  # ASF default: false (private tracker — reporter never gets a
  # link).
  # Override when: a public tracker where the reporter is added as
  # a collaborator.
  # Consumed by: security-issue-import, canned-responses templating.
  reporter_has_access: false

  # Whether the tracker drives a board / kanban view. When false,
  # skills skip column transitions entirely.
  # ASF default: true.
  # Override when: an adopter using only labels + milestones.
  # Consumed by: pr-management-triage, security-issue-sync.
  project_board_enabled: true

  # Template the skills use to compose a "link back to the skill
  # docs as seen in this repo" URL. `<skill>` is the slug under
  # .claude/skills/.
  # ASF default: tracker default branch on github.com.
  # Override when: a non-GitHub tracker — replace with the platform's
  # equivalent file-view URL shape.
  # Consumed by: pr-management-mentor, canned-responses (footer link).
  skill_url_template: "https://github.com/<tracker>/blob/main/.claude/skills/<skill>/SKILL.md"

  # Tracker body-field heading names — the literal `###` headings
  # the skills read and write under in the tracker's issue
  # template. The skill code refers to these by *role*; this map
  # binds role -> concrete heading.
  # ASF default: the existing airflow-s headings.
  # Override when: an adopter with a different issue-template shape
  # — change the headings here, not the skills.
  # Consumed by: every skill that reads/writes the issue body.
  body_fields:
    cve_link: "CVE tool link"
    mailing_thread: "Mailing list thread URL"
    affected_versions: "Affected versions"

  # Tracker labels — role -> concrete label name. Skills speak in
  # roles; this map binds role -> literal label.
  # ASF default: the airflow-s label set.
  # Override when: a tracker with a different label vocabulary.
  # Consumed by: security-issue-triage, security-issue-sync,
  # pr-management-triage.
  labels:
    security_marker: "security"
    needs_triage: "needs triage"
    pr_open: "pr created"
    pr_merged: "pr merged"
    cve_allocated: "cve allocated"
    not_cve_worthy: "not cve worthy"

Scope detection

scope_detection:
  # Whether the project distinguishes scope sub-products (e.g.
  # airflow vs providers vs chart). When false, every issue maps
  # to the single product declared in the `product` block.
  # ASF/Airflow default: true.
  # Override when: a single-artifact project — set to false and
  # drop the labels map.
  # Consumed by: security-issue-triage, generate-cve-json,
  # security-issue-sync.
  enabled: true

  # Scope label -> sub-product mapping. Each entry binds a tracker
  # label to the CVE `product` field value, the package-name shape
  # the advisory will use, and the upstream path prefix the skill
  # uses to confirm a PR really touches that scope.
  # ASF/Airflow default: the three existing scope labels.
  # Override when: a project with different scope axes — keep the
  # `product`/`packageName`/`path_prefix` triad shape.
  # Consumed by: security-issue-triage, generate-cve-json.
  labels:
    airflow:
      product: "Apache Airflow"
      packageName: "apache-airflow"
      path_prefix: "^(airflow-core/|airflow/(?!providers/)|airflow-ctl/)"
    providers:
      product: "Apache Airflow"
      packageName: "apache-airflow-providers-<provider>"
      path_prefix: "^providers/"
    chart:
      product: "Apache Airflow Helm Chart"
      packageName: "apache-airflow-helm-chart"
      path_prefix: "^chart/"

Release process

release_process:
  # Cascade of sources skills consult to resolve "who is RM for
  # version X". First match wins; later entries are tried only if
  # earlier entries fail to surface a handle.
  # ASF default: the project's release-trains.md roster file, then
  # the wiki release-managers page, then the dev@ mailing-list
  # VOTE/RESULT threads.
  # Override when: non-ASF — collapse to whatever roster source the
  # project keeps. Drop entries that don't apply.
  # Consumed by: security-issue-sync, security-issue-fix (PR
  # reviewer assignment).
  release_manager_lookup_cascade:
    - kind: roster_file
      path: "release-trains.md"
    - kind: wiki_url
      url: "https://cwiki.apache.org/confluence/display/<PROJECT>/Release+Managers"
    - kind: mailing_list_vote_thread
      list: "<dev-list>"

  # Artifact registries where the project publishes releases — the
  # skills cross-check that a fix has shipped here before flipping
  # the issue to "fix released".
  # ASF default: [pypi, artifacthub] (Python wheels + Helm chart).
  # Override when: non-Python projects (`maven`, `npm`, ...) or
  # projects that publish elsewhere.
  # Consumed by: security-issue-sync, generate-cve-json
  # (references[] population).
  artifact_registries: [pypi, artifacthub]

  # Milestones the skills treat as "stale" — i.e. anything still
  # pinned to one of these is overdue for re-targeting. Listed as
  # exact milestone-name matches.
  # ASF/Airflow default: the current airflow-s stale-milestone list.
  # Override when: replace with the adopter's stale-milestone names.
  # Consumed by: security-issue-sync, pr-management-triage.
  stale_milestones:
    - "Airflow 2.x"
    - "Airflow 2.10.x"
    - "Airflow 3.0.x"

  # Whether the upstream repo uses a newsfragments / changelog
  # fragment tool, and which one. Skills hook this when proposing
  # a fix — the fix PR must include a fragment.
  # ASF/Airflow default: enabled with towncrier.
  # Override when: projects without a fragment tool (`enabled:
  # false`) or with a different tool (reno, changie, ...).
  # Consumed by: security-issue-fix, issue-fix-workflow.
  newsfragments:
    enabled: true
    tool: towncrier

Roster

roster:
  # Source of truth for the security team membership and the
  # bare-name -> handle mapping. Selects how the skills resolve
  # "is X on the security team".
  # `tracker-collaborators` = read the tracker repo's collaborator
  # list; `roster-file:<path>` = read a checked-in file (path
  # relative to <project-config>/); `inline:<list>` = a literal
  # list spelled out below.
  # ASF default: roster-file:release-trains.md (the canonical
  # source for the Airflow security team).
  # Override when: non-ASF — pick whichever shape matches the
  # adopter's source of truth.
  # Consumed by: security-issue-sync, security-cve-allocate,
  # security-issue-triage.
  source: roster-file:release-trains.md

  # Bare-name -> @handle mapping. Mailing-list threads frequently
  # reference contributors by first name only; this map binds
  # those bare names to GitHub handles so the skills can produce
  # @-mentions on the tracker.
  # ASF/Airflow default: the existing airflow-s bare-name map.
  # Override when: adapt to the adopter's roster — add/remove
  # entries as needed.
  # Consumed by: security-issue-sync, pr-management-mentor.
  bare_name_handles:
    Jarek: "@potiuk"
    Ash: "@ashb"
    Kaxil: "@kaxil"
    Ephraim: "@ephraimbuddy"
    Jed: "@jedcunningham"

  # Release-manager handles, ordered by recency of train ownership.
  # First handle is the current default RM; the rest are the
  # historical RMs the skill falls back to when assigning legacy
  # trains.
  # ASF/Airflow default: the current RM order from release-trains.md.
  # Override when: keep in sync with `release-trains.md`.
  # Consumed by: security-issue-sync, security-issue-fix.
  release_managers:
    - "@ephraimbuddy"
    - "@jedcunningham"
    - "@potiuk"
    - "@kaxil"

Product

product:
  # Human-readable product name — what lands in the CVE record's
  # `product` field and what canned responses address the product
  # as.
  # ASF/Airflow default: Airflow.
  # Override when: any other project — replace with the canonical
  # short name.
  # Consumed by: generate-cve-json, canned-responses templating.
  name: Airflow

  # Package name shape for the primary artifact — used by the
  # advisory templating and the CVE JSON `affected[].packageName`.
  # ASF/Airflow default: apache-airflow (PyPI distribution).
  # Override when: any other project — use the package-registry
  # name (PyPI / npm / Maven / ...).
  # Consumed by: generate-cve-json, canned-responses templating.
  package_name: apache-airflow

  # Regex matched against changed paths in an upstream PR to
  # confirm "this PR really touches the product". Used as a
  # backstop sanity check in the fix flow.
  # ASF/Airflow default: starts with `airflow` (matches
  # airflow/, airflow-core/, airflow-ctl/, etc.).
  # Override when: any other repo layout.
  # Consumed by: security-issue-fix, pr-management-triage.
  code_pointer_path_prefix: "^airflow"

  # Prefixes the title-normalization skill strips when normalising
  # an inbound subject line into a CVE title. Matched at the start
  # of the subject, case-insensitively, in order; the first match
  # wins and is removed.
  # ASF/Airflow default: the existing airflow-s strip cascade.
  # Override when: any other project — replace with the adopter's
  # subject-prefix conventions.
  # Consumed by: title-normalization, generate-cve-json,
  # canned-responses templating.
  subject_prefix_strip:
    - "[SECURITY]"
    - "[Security Report]"
    - "Re:"
    - "Fwd:"
    - "Airflow:"
    - "Apache Airflow:"

  # Prefix the affected-versions extractor looks for in mailing-list
  # bodies — reporters typically write "Airflow 2.10.0 is affected".
  # Skill strips this prefix to leave the bare version literal.
  # ASF/Airflow default: "Airflow".
  # Override when: any other product — the literal product token
  # reporters use in version expressions.
  # Consumed by: security-issue-sync, generate-cve-json.
  affected_version_extract_prefix: "Airflow"

Pointers to sibling files