Table of Contents generated with DocToc

security-tracker-stats.md (template)

Per-project configuration consumed by the security-tracker-stats-dashboard skill. Copy this file into your project's <project-config>/ directory and edit the values below. Everything is optional — the skill falls back to tools/security-tracker-stats-dashboard/default-config.yaml when a key is unset.

YAML config path

tracker_stats_config: .apache-magpie-overrides/security-tracker-stats.yaml

The renderer reads its configuration from the YAML file pointed at by the TRACKER_STATS_CONFIG env var. The skill resolves this from tracker_stats_config: above (interpreting it relative to the adopter repo root). Adopters who want the framework's defaults verbatim can leave this unset; the skill will skip the overlay step.

The YAML schema is documented inline at tools/security-tracker-stats-dashboard/default-config.yaml.

Default output path

tracker_stats_output: tmp/tracker_stats.html

The skill writes the rendered HTML to this path (relative to the adopter repo root, or absolute) when the user does not pass an explicit <output-path> argument. The reference <org>/<repo> adopter uses tmp/<project>_monthly.html (committed into tmp/ as the canonical artefact for security-team review).

Cache directory

tracker_stats_cache: /tmp/tracker-stats-cache

Where the fetch scripts persist their cache. Safe to delete (forces a full re-fetch). The skill resolves this to the TRACKER_STATS_CACHE env var.

Refresh cadence

tracker_stats_refresh_hours: 24

The skill considers the cache stale when issues.json is older than this many hours, and proposes a refresh before re-rendering. Lower this for fast-moving trackers; raise it for trackers where the dashboard is reviewed weekly or monthly.

Rejected-without-tracker ledger

rejections_ledger_label: rejections-ledger

Lives in the renderer's YAML overlay (the file pointed at by tracker_stats_config: above), not in project.md. Names the label on the single open ledger issue that records reports the security-issue-import skill rejected with a canned reply without creating a tracker — see the Rejected-without-tracker ledger note in project.md for the convention. The renderer identifies any issue carrying this label as the ledger, excludes it from all tracker classification, and parses its comments for the <!-- rejection v1 --> / <!-- rejection-backfill v1 count: N --> markers to produce a rejected (no tracker) count (a per-bucket area series plus a <dated> + <historical> = <total> headline).

Set to null to disable the stat entirely (no ledger issue needed). The ASF default is rejections-ledger, matching tracker.labels.rejections_ledger in project.md. To turn the stat on, create the open ledger issue, label it, and keep this knob pointed at the same label.

Example overlay (security-tracker-stats.yaml)

A minimal overlay that swaps to quarterly buckets and adds a project-specific milestone:

buckets: quarterly

rejections_ledger_label: rejections-ledger

milestones:
  - date: 2026-04-20
    label: skill adoption
  - date: 2026-09-01
    label: handover to PMC sec team

A bigger overlay that renames the scope labels for a non-ASF adopter and removes the upstream-PR charts entirely (because fixes land in many repos, not a single <upstream>):

upstream_repo: null

scope_labels: [core, plugins, docs]

milestones: []

# Re-state the full categories list to align with the project's
# label conventions. The framework's default categories assume
# `needs triage`, `pr merged`, `fix released`, `announced - emails
# sent`, `cve allocated` — projects with different label vocabularies
# need to re-state predicates explicitly.
categories:
  - name: fixed_released
    color: "#2ca02c"
    predicate:
      any_of:
        - any_label: [released]
        - all_of:
            state: closed
            state_reason: COMPLETED
            any_label: [security-fix]
  - name: closed_other
    color: "#888888"
    predicate:
      state: closed
  - name: open_untriaged
    color: "#d62728"
    predicate:
      all_of:
        state: open
        any_of:
          - any_label: [needs triage]
          - no_scope_label: true
  - name: open_pr_merged
    color: "#e67e22"
    predicate:
      all_of:
        state: open
        any_label: [pr merged]
  - name: open_triaged
    color: "#f1c40f"
    predicate:
      state: open