blob: a38f0be40b28ef245f3f2b9ec0c1ae14818d2204 [file] [view]
<!-- SPDX-License-Identifier: Apache-2.0
https://www.apache.org/licenses/LICENSE-2.0 -->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [TODO: `<Project Name>` — project manifest](#todo-project-name--project-manifest)
- [Identity](#identity)
- [Repositories](#repositories)
- [Mailing lists](#mailing-lists)
- [Tools enabled](#tools-enabled)
- [CVE tooling](#cve-tooling)
- [GitHub project board](#github-project-board)
- [Mail sources](#mail-sources)
- [Backend declaration](#backend-declaration)
- [Per-backend config](#per-backend-config)
- [Issue-template fields](#issue-template-fields)
- [Security workflow configuration](#security-workflow-configuration)
- [CVE authority](#cve-authority)
- [Governance](#governance)
- [Security inbox](#security-inbox)
- [Forwarders](#forwarders)
- [Mail provider](#mail-provider)
- [Archive system](#archive-system)
- [Project metadata](#project-metadata)
- [Tracker](#tracker)
- [Scope detection](#scope-detection)
- [Release process](#release-process)
- [Roster](#roster)
- [Product](#product)
- [Pointers to sibling files](#pointers-to-sibling-files)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<!-- SPDX-License-Identifier: Apache-2.0
https://www.apache.org/licenses/LICENSE-2.0 -->
# TODO: `<Project Name>` — project manifest
This is the **project configuration** for `TODO: <project-name>`.
Every skill under [`../../.claude/skills/`](../../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:
```bash
grep -n TODO projects/<name>/project.md
```
## Identity
| Key | Value |
|---|---|
| `organization` | TODO: the organization whose defaults this project inherits — e.g. `ASF` ([`organizations/ASF/`](../../organizations/ASF/)). Default `independent` ([`organizations/independent/`](../../organizations/independent/)). See [`organizations/README.md`](../../organizations/README.md). |
| `project_name` | TODO: e.g. `Apache Foo` |
| `vendor` | TODO: e.g. `Apache Software Foundation` |
| `short_name` | TODO: e.g. `Foo` |
| `product_family_url` | TODO: 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
| Key | Value | Purpose |
|---|---|---|
| `tracker_repo` | TODO: e.g. `foo-s/foo-s` | Private security tracker (this repo) |
| `tracker_repo_url` | TODO | |
| `tracker_default_branch` | TODO: e.g. `main` | Default PR target for the tracker repo |
| `tracker_project_board_url` | TODO: URL of the GitHub Project V2 board, if any | Security board |
| `upstream_repo` | TODO: e.g. `apache/foo` | Public codebase where fixes land |
| `upstream_repo_url` | TODO | |
| `upstream_default_branch` | TODO: e.g. `master` (older default) or `main` | Upstream's default branch — what `<default-branch>` resolves to. Distinct from `tracker_default_branch` (the security tracker repo's PR target) |
| `upstream_agents_md_url` | TODO: `https://github.com/<upstream>/blob/main/AGENTS.md` | Conventions this repo mirrors |
| `upstream_contributing_docs_url` | TODO | |
| `upstream_genai_disclosure_anchor` | TODO: URL + anchor for the project's Gen-AI disclosure guideline | |
| `upstream_security_policy_url` | TODO: `https://github.com/<upstream>/security/policy` | |
## Mailing lists
| Key | Value | Notes |
|---|---|---|
| `security_list` | TODO: e.g. `security@foo.apache.org` | Inbound reports; **not** publicly archived |
| `private_list` | TODO: e.g. `private@foo.apache.org` | PMC escalation; **not** publicly archived |
| `users_list` | TODO: e.g. `users@foo.apache.org` | Public advisories end up here; publicly archived |
| `dev_list` | TODO: e.g. `dev@foo.apache.org` | Release `[RESULT][VOTE]` threads; publicly archived |
| `announce_list` | TODO: e.g. `announce@apache.org` | Cross-project announcement list; publicly archived |
| `commits_list` | TODO: e.g. `commits@foo.apache.org` | Publicly archived |
Only URLs on publicly archived lists may appear in CVE `references[]` as
`vendor-advisory`; see `../../AGENTS.md` and
[`security-model.md`](security-model.md).
The foundation-wide security forwarding address (e.g. `security@apache.org`
for ASF projects) is org-level — inherited from your organization's
`security_inbox.foundation_security_address`. Do not declare it here.
## Tools enabled
| Capability | Tool | Adapter directory | Config knobs declared here |
|---|---|---|---|
| Issue tracking + project board | `github` | [`../../tools/github/`](../../tools/github/) | `tracker_repo`, `upstream_repo`, `github_project_board_*`, `issue_template_fields` |
| Source control (VCS) | `github` (Git) — replaceable with a non-Git VCS | [`../../tools/github/source-control.md`](../../tools/github/source-control.md) | `upstream_repo`, `default_branch`; for a non-Git VCS declare the sibling tool + its working-copy URL |
| Inbound email / drafts | `<one or more mail-source backends>` | [`../../tools/mail-source/contract.md`](../../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](#mail-sources) below — declare each backend's role (primary / preferred-for-`<op>` / fallback / optional) and `mandatory` flag |
| CVE allocation + record mgmt | *org-level* — inherited from `organizations/<org>/organization.md → cve_authority.tool`; for ASF: `vulnogram` ([`tools/cve-tool-vulnogram/`](../../tools/cve-tool-vulnogram/)), for independent: `mitre-form` | — | override in [CVE authority](#cve-authority) only if this project differs from its org |
| Project metadata (rosters / people / releases) | *org-level* — inherited from `organizations/<org>/organization.md → project_metadata.kind`; for ASF: `apache-projects` ([`tools/apache-projects/`](../../tools/apache-projects/)), for independent: `none` | — | override in [Project metadata](#project-metadata) only if this project differs from its org |
| Release comms | TODO: the backend that carries release announcements — for ASF: `dev_list` / `announce_list` / `users_list`; for GitHub Releases leave blank | — | whichever release-comms keys the org default or per-project override declares |
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
The CNA tool, allocation URL, record URL template, and allocation gate are
**org-level** — inherited from your organization's `cve_authority` and
`governance` blocks (see
[`organizations/ASF/organization.md`](../../organizations/ASF/organization.md)
for ASF defaults,
[`organizations/independent/organization.md`](../../organizations/independent/organization.md)
for the GitHub-native baseline). Override a key in the
[Security workflow configuration → CVE authority](#cve-authority) block only
if this project's CNA setup genuinely differs from its organization.
For **ASF adopters**, fill in the per-project CNA queue fields below — each
ASF project has its own queue slug and org UUID, so these are not org-level:
| Key | Value |
|---|---|
| `asf_org_id` | TODO: project's CNA org UUID — e.g. `f0158376-9dc2-43b6-827c-5f631a4d8d09` |
| `cna_private_owner` | TODO: e.g. `foo` (CNA_private.owner — the project slug inside the ASF CNA queue) |
| `cna_private_projecturl` | TODO: e.g. `https://foo.apache.org/` |
| `cna_private_userslist` | TODO: 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`](../../tools/github/project-board.md#introspection--re-fetch-the-option-ids).
If the project does not run a board, leave the table blank — skills
treat missing board config as *"no board reconciliation"*.
| Key | Value |
|---|---|
| `project_board_url` | TODO |
| `project_board_number` | TODO |
| `project_board_node_id` | TODO |
| `status_field_node_id` | TODO |
**`Status` column → option-ID mapping** (re-fetch if any write
returns `not found`):
| Column | Option ID |
|---|---|
| `Needs triage` | TODO |
| `Assessed` | TODO |
| `CVE allocated` | TODO |
| `PR created` | TODO |
| `PR merged` | TODO |
| `Fix released` | TODO |
| `Announced` | TODO |
## Mail sources
The skills treat every supported mail backend the same way —
through the abstract operations defined in
[`../../tools/mail-source/contract.md`](../../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).
| Backend | Role | Mandatory | Notes |
|---|---|---|---|
| TODO: `gmail` | TODO: e.g. `primary` | TODO: `yes` / `no` | TODO: e.g. "Triager Gmail account subscribed to `<security-list>` and `<private-list>`" |
| TODO: `ponymail` | TODO: e.g. `fallback` or `preferred for thread_url` | TODO: `yes` / `no` | TODO: e.g. "Read-only archive backstop; install per [`tools/ponymail/tool.md`](../../tools/ponymail/tool.md)" |
| TODO: *(add more rows as needed — `imap`, `mbox`, project-specific adapter)* | | | |
> **Mail backend selection is org-level.** The `mail_provider` block in
> your organization manifest sets the primary and fallback backends
> (for ASF: `primary: gmail-mcp`, `fallback: ponymail`; for independent:
> `primary: none`, `fallback: none`). Only declare backends here that
> override or extend what the organization manifest provides. For ASF
> projects where PonyMail is the inherited fallback, declare it here only
> to change its `mandatory` flag or role for this specific project; the
> backend itself is already wired by the organization. Install PonyMail per
> [`../../tools/ponymail/tool.md`](../../tools/ponymail/tool.md#keeping-the-checkout-current).
Reference adapter docs:
[`tools/gmail/tool.md`](../../tools/gmail/tool.md) (full read+write),
[`tools/ponymail/tool.md`](../../tools/ponymail/tool.md) (read-only ASF archive),
[`tools/mail-source/imap/README.md`](../../tools/mail-source/imap/README.md) (stub),
[`tools/mail-source/mbox/README.md`](../../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.
| Key | Backend | Value |
|---|---|---|
| `security_list_domain` | `gmail` | TODO: e.g. `security.foo.apache.org` — Gmail `list:` operator uses the domain form |
| `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/<hash>?<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` |
| `imap_drafts_folder` | `imap` | TODO: e.g. `Drafts` (or leave blank to declare `create_draft` unsupported on this adapter) |
| `mbox_archive_path` | `mbox` | TODO: 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`](../../tools/github/issue-template.md);
the concrete names below are what skills read and write for this
project.
| Role (generic) | Field name | Template type | Required? |
|---|---|---|---|
| `issue-description` | TODO | `textarea` | TODO |
| `public-summary` | TODO | `textarea` | TODO |
| `affected-versions` | TODO | `input` | TODO |
| `security-thread` | TODO | `input` | TODO |
| `public-advisory-url` | TODO | `input` | TODO |
| `reporter-credit` | TODO | `input` | TODO |
| `pr-with-fix` | TODO | `input` | TODO |
| `cwe` | TODO | `input` | TODO |
| `severity` | TODO | `dropdown` | TODO |
| `cve-tool-link` | TODO | `input` | TODO |
## Security workflow configuration
Skills resolve every workflow knob from the three-layer chain
`project.md → organizations/<org>/organization.md → framework default`
(see [`AGENTS.md` § Configuration resolution order](../../AGENTS.md#configuration-resolution-order)).
The **organization** you named under *Identity* supplies the org-wide
defaults — the CNA tool, the governance gate, the mail / forwarder /
archive backends, the project-metadata source, and the release-manager
lookup cascade. For an ASF project these resolve to the Vulnogram /
PonyMail / `apache-projects-mcp` / ASF-security values in
[`organizations/ASF/organization.md`](../../organizations/ASF/organization.md);
`organization: independent` inherits the GitHub-native baseline in
[`organizations/independent/organization.md`](../../organizations/independent/organization.md).
**Declare below only what is specific to this project.** Each block that
is purely org-level says so and shows nothing — copy the matching key
from the organization manifest down into that block only to override it
(the project value wins). The blocks that every adopter fills in keep
their per-project keys.
### CVE authority
Org-level — inherited from your organization's `cve_authority` block
(CNA tool, allocate / record / source-tab URLs, state mapping,
propagation, allocation-email flag, reviewer channel). Override a single
key here only if this project's CNA setup differs from its organization.
### Governance
Org-level except the escalation contact: the allocation gate, gate
label, release-vote gating, private governance list, and roster URL are
inherited. Declare this project's escalation contact:
```yaml
governance:
# GitHub handle (or external contact) the skills cc / @-mention when
# escalating beyond the security team.
# Consumed by: security-issue-sync, pr-management-triage.
escalation_contact: "@<escalation-contact>"
```
### Security inbox
Org-level except the concrete address: the inbox `kind`, the foundation
security address, the `has_forwarder_relay` flag, and the list filter are
inherited. Declare this project's inbound address:
```yaml
security_inbox:
# The concrete inbound address / channel ID / form URL for this project.
# Consumed by: security-issue-import, security-issue-sync, canned-responses.
address: <security-list>
```
### Forwarders
Org-level — inherited from your organization's `forwarders` block (which
relay adapters are enabled and their per-adapter detect / credit rules).
Override here only to enable an extra relay this project uses.
### Mail provider
Org-level — inherited from your organization's `mail_provider` block
(primary + fallback mail backends). Override here only if this project
reads mail from a different backend than its organization.
### Archive system
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.
### Project metadata
Org-level — inherited from your organization's `project_metadata` block
(roster / people / releases backend + whether it is mandatory). Override
here only if this project uses a different metadata source.
### Tracker
The tracker `platform`, `board`, `visibility`, and `skill_url_template`
are org-level defaults — override them here only if this project differs
(e.g. a project that runs its security tracker publicly sets
`visibility: public`). Declare this project's per-tracker vocabulary:
```yaml
tracker:
# Whether the reporter can see the tracker issue once opened.
reporter_has_access: false
# Whether the tracker drives a board / kanban view.
project_board_enabled: true
# Body-field heading names — role -> the concrete `###` heading in this
# project's issue template. Skills refer to these by role.
# 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 -> the concrete label name in this project.
# 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"
# Label on the single open "rejected without tracker" ledger issue
# (see below). NOT the security_marker label.
rejections_ledger: "rejections-ledger"
```
#### Rejected-without-tracker ledger
The `security-issue-import` skill sometimes rejects a report with a
canned reply **without creating a tracker** (the disposition lives only
on the mail thread). To keep those rejections countable, the team
records each one as a comment on a single dedicated **ledger issue** in
`tracker_repo`: one **open** issue, labelled with the
`tracker.labels.rejections_ledger` value (default `rejections-ledger`)
and **not** carrying the security-marker label.
Adopters who want the *rejected without tracker* dashboard stat must:
1. **Create the ledger issue** once in `tracker_repo` and label it
`rejections-ledger` (keep it open; the skills resolve it via
`gh issue list --repo <tracker> --state open --label
rejections-ledger`).
2. **Set the dashboard knob.** Point
`security-tracker-stats.md → rejections_ledger_label` (or the
`rejections_ledger_label:` key in the renderer's YAML overlay) at the
same label. Set it to `null` to disable the stat — then no ledger
issue is needed.
Each rejection comment carries a machine-parseable block
(`<!-- rejection v1 -->` with `date:` / `reporter:` / `canned:` /
`thread:` / `summary:` lines); a one-time historical backfill is a
single `<!-- rejection-backfill v1 count: N -->` comment. The
`security-tracker-stats-dashboard` renderer parses these and excludes the
ledger issue from all tracker classification. Closes handled by
`security-issue-invalidate` are **not** ledger entries.
### Scope detection
Per-project — whether this project distinguishes scope sub-products, and
the label → sub-product map:
```yaml
scope_detection:
# When false, every issue maps to the single product in the `product` block.
# Consumed by: security-issue-triage, generate-cve-json, security-issue-sync.
enabled: true
# Scope label -> sub-product: tracker label -> CVE product / packageName
# / upstream path-prefix the skill uses to confirm a PR touches that scope.
labels:
<scope-label>:
product: "<Product Name>"
packageName: "<package-name>"
path_prefix: "<path-prefix-regex>"
<secondary-scope-label>:
product: "<Secondary Product Name>"
packageName: "<secondary-package-name>"
path_prefix: "<secondary-path-prefix-regex>"
```
### Release process
The release-manager lookup cascade and artifact registries are org-level
and inherited. Declare this project's stale milestones and changelog
fragment tool:
```yaml
release_process:
# Milestones the skills treat as "stale" (overdue for re-targeting) —
# exact milestone-name matches.
# Consumed by: security-issue-sync, pr-management-triage.
stale_milestones:
- "<stale-milestone-1>"
- "<stale-milestone-2>"
# Whether the upstream repo uses a changelog-fragment tool, and which one.
# Consumed by: security-issue-fix, issue-fix-workflow.
newsfragments:
enabled: true
tool: <fragment-tool>
```
### Roster
The roster `source` is org-level and inherited. Declare this project's
bare-name → handle map and release managers:
```yaml
roster:
# Mailing-list threads reference contributors by first name; this binds
# those to GitHub handles for @-mentions.
# Consumed by: security-issue-sync, pr-management-mentor.
bare_name_handles:
# Example (replace with your project's contributors):
"<FirstName>": "@<handle>"
# Release-manager handles, current first. Keep in sync with release-trains.md.
# Consumed by: security-issue-sync, security-issue-fix.
release_managers:
# Example (replace with your project's release managers):
- "@<handle>"
```
### Product
Per-project — the product identity used in CVE records, advisories, and
title normalization:
```yaml
product:
# Human-readable product name — lands in the CVE record's `product` field.
# Consumed by: generate-cve-json, canned-responses templating.
name: <ProjectShortName>
# Package-name shape for the primary artifact (PyPI / npm / Maven).
# Consumed by: generate-cve-json, canned-responses templating.
package_name: <package-name>
# Regex matched against changed paths in an upstream PR to confirm
# "this PR really touches the product" — a backstop in the fix flow.
# Consumed by: security-issue-fix, pr-management-triage.
code_pointer_path_prefix: "<code-path-prefix-regex>"
# Prefixes the title-normalization skill strips from an inbound subject
# when building a CVE title (matched at the start, case-insensitively).
# Consumed by: title-normalization, generate-cve-json, canned-responses.
subject_prefix_strip:
- "[SECURITY]"
- "[Security Report]"
- "Re:"
- "Fwd:"
- "<vendor>:"
- "<vendor> <product>:"
# Prefix the affected-versions extractor strips to leave the bare version.
# Consumed by: security-issue-sync, generate-cve-json.
affected_version_extract_prefix: "<ProjectShortName>"
```
## Pointers to sibling files
- [`release-trains.md`](release-trains.md) — fast-moving release state, release-manager attribution, security-team roster.
- [`milestones.md`](milestones.md) — milestone naming conventions.
- [`scope-labels.md`](scope-labels.md) — scope label → CVE product mapping.
- [`security-model.md`](security-model.md) — Security-Model URL + anchors.
- [`title-normalization.md`](title-normalization.md) — CVE title strip cascade.
- [`fix-workflow.md`](fix-workflow.md) — fork / toolchain / commit-trailer specifics.
- [`naming-conventions.md`](naming-conventions.md) — project-specific editorial rules.
- [`canned-responses.md`](canned-responses.md) — reporter-facing reply templates.
- [`skill-sources.md`](skill-sources.md) — trusted external skill sources this project pulls skills from (the install gate).
- [`README.md`](README.md) — project file index + onboarding checklist.