"""Built-in seed catalogue: severity tiers + the reply-template library. This module is the **single source of truth** for the shipped defaults. Migration ``533`` seeds the tables from here, and the admin console's "restore default" action re-reads from here, so there is exactly one copy of every template body in the tree. Rows seeded from this catalogue carry ``is_builtin=True``: they can be edited and disabled but not deleted, because the flows that reference them by key (the reply picker's suggested template per triage outcome) must always resolve. Template bodies are **English only** — the audience is an external security researcher who wrote to us in English. That is a deliberate exception to the platform's tri-lingual rule, which governs Helix's own UI (the template *names* and *categories* shown in the picker ARE translated, via ``bounty.templateName.`` i18n keys). """ from __future__ import annotations from typing import TypedDict from app.domains.bounty import constants as const class SeverityTierSeed(TypedDict): key: str label_zh: str label_en: str label_ja: str default_reward_usd: int max_reward_usd: int | None fix_sla_days: int | None color: str sort_order: int #: Reward ladder as approved 2026-08-24. ``max_reward_usd`` is a #: guardrail on the per-report override, not a promise to the #: researcher; ``fix_sla_days`` drives the remediation-overdue signal. SEVERITY_TIERS: tuple[SeverityTierSeed, ...] = ( { "key": "critical", "label_zh": "严重", "label_en": "Critical", "label_ja": "重大", "default_reward_usd": 1500, "max_reward_usd": 5000, "fix_sla_days": 7, "color": "#B91C1C", "sort_order": 10, }, { "key": "high", "label_zh": "高危", "label_en": "High", "label_ja": "高", "default_reward_usd": 800, "max_reward_usd": 2000, "fix_sla_days": 14, "color": "#EF4444", "sort_order": 20, }, { "key": "medium", "label_zh": "中危", "label_en": "Medium", "label_ja": "中", "default_reward_usd": 300, "max_reward_usd": 800, "fix_sla_days": 30, "color": "#F59E0B", "sort_order": 30, }, { "key": "low", "label_zh": "低危", "label_en": "Low", "label_ja": "低", "default_reward_usd": 100, "max_reward_usd": 300, "fix_sla_days": 60, "color": "#0EA5E9", "sort_order": 40, }, { "key": "informational", "label_zh": "告知", "label_en": "Informational", "label_ja": "情報提供", "default_reward_usd": 0, "max_reward_usd": 100, "fix_sla_days": None, "color": "#94A3B8", "sort_order": 50, }, ) SEVERITY_KEYS: tuple[str, ...] = tuple(t["key"] for t in SEVERITY_TIERS) class TemplateSeed(TypedDict): key: str name_zh: str name_en: str name_ja: str category: str subject: str body: str variables: list[str] sort_order: int # ── Shared placeholder vocabulary ─────────────────────────────────── # # Rendering replaces ``{token}`` for the tokens listed below and leaves # anything else untouched (see ``rendering.render_template``), so a stray # brace in an operator-authored template can never raise. # # {researcher_name} greeting name, falls back to "submitter" # {report_code} BB-2026-001 — also used as the subject tag # {report_title} the report's own title # {affected_system} free-text target (tidbcloud.com, docs site, …) # {cve_id} CVE identifier when the report cites one # {amount_usd} formatted reward, e.g. "100" # {severity_label} English severity label # {signer_name} from the bounty.reply_signature setting # {signer_title} # {team_name} # {company_name} # {entity_block} legal entity + address used on invoices # {security_policy_url} _POLICY_URL = "https://www.pingcap.com/security" _CORE_PRODUCTS = ( "TiDB, TiKV, TiFlash, PD" ) _CORE_DOMAINS = ( "tidbcloud.com, tidb-cloud.com, tidbapi.com" ) REPLY_TEMPLATES: tuple[TemplateSeed, ...] = ( { "key": "thanks_generic", "name_zh": "致谢(不涉及奖金)", "name_en": "General appreciation (no bounty stated)", "name_ja": "謝辞(報奨金の言及なし)", "category": const.REPLY_CATEGORY_ACK, "subject": "Re: your security report to PingCAP [{report_code}]", "body": """Dear {researcher_name}, We are writing to express our sincerest appreciation for submitting the vulnerability to PingCAP. Your contribution is immensely valuable to us and we cannot thank you enough for bringing this matter to our attention. If you have any further feedback or concerns, please do not hesitate to reach out to us via email. Additionally, you can find more information about our security practices and procedures by visiting this link: {security_policy_url} Once again, we extend our heartfelt gratitude for your dedication to PingCAP. We greatly appreciate your help in making our system more secure and reliable. We hope to receive more valuable bug reports from you in the future. Best regards, The {company_name} Team""", "variables": [ "report_code", "security_policy_url", "company_name", "researcher_name", ], "sort_order": 10, }, { "key": "under_evaluation", "name_zh": "已收到·评估中(按级别给奖)", "name_en": "Acknowledged — under evaluation", "name_ja": "受領・評価中", "category": const.REPLY_CATEGORY_ACK, "subject": "Re: your security report to PingCAP [{report_code}]", "body": """Dear {researcher_name}, We would like to thank you for bringing to our attention the vulnerability in our system. Please be assured that we take security matters very seriously and are committed to addressing any issues as quickly and efficiently as possible. We will carefully evaluate the impact of the vulnerability you have reported, and based on our assessment, we will assign it an appropriate severity level. As part of our commitment to security, we offer rewards to those who report vulnerabilities to us. Rest assured that we will provide a fair and just reward based on the severity of the vulnerability you have identified. Once again, thank you for your attention to this matter. We truly value your contribution to improving the security of our system, and we look forward to working with you to make it even better. Best regards, The {company_name} Team""", "variables": ["report_code", "company_name", "researcher_name"], "sort_order": 20, }, { "key": "out_of_scope_general", "name_zh": "不在收录范围(通用)", "name_en": "Out of scope (general)", "name_ja": "対象範囲外(一般)", "category": const.REPLY_CATEGORY_OUT_OF_SCOPE, "subject": "Re: your security report to PingCAP [{report_code}]", "body": """Dear {researcher_name}, Greetings! First and foremost, we would like to express our gratitude for your interest in {company_name}. We highly value the vulnerabilities you have submitted, and upon receiving your email, we promptly conducted the necessary investigation and verification. After thorough examination, we regret to inform you that the issue you have raised does not fall within the scope of our coverage. The following situations do not qualify as security vulnerabilities: - Physical attacks - Social engineering attacks or proximity attacks - Missing HTTP security headers or enabling specific HTTP methods - Email Sender Policy Framework (SPF) issues You can find more information at this link: {security_policy_url} Once again, we appreciate your attention to {company_name}, and we encourage you to provide us with more valuable questions in the future. Upon assessing the impact of the identified issues, we will duly reward you according to our standards. Best regards, {company_name}""", "variables": [ "researcher_name", "report_code", "company_name", "security_policy_url", ], "sort_order": 30, }, { "key": "out_of_scope_tls", "name_zh": "不在收录范围(TLS/SSL 配置类)", "name_en": "Out of scope — TLS/SSL configuration", "name_ja": "対象範囲外(TLS/SSL 設定)", "category": const.REPLY_CATEGORY_OUT_OF_SCOPE, "subject": "Re: your security report to PingCAP [{report_code}]", "body": """Hello {researcher_name}, Thank you very much for taking the time to review our services and share your findings with us. We truly appreciate your efforts in helping us maintain the security of our products. As outlined in our security policy ({security_policy_url}), we generally do not consider reports related solely to TLS/SSL configuration, cipher suites, or similar categories as in-scope, unless a clear, demonstrable security impact can be shown. If you believe your findings affect our core products — such as """ + _CORE_PRODUCTS + """ — or our key domains and services, including """ + _CORE_DOMAINS + """, we would be happy to review any additional technical details you can provide for further evaluation. Once again, thank you for your attention to our security. We value contributions from the security community and look forward to hearing from you again in the future. Best regards, {signer_name} {signer_title} {company_name}""", "variables": [ "report_code", "security_policy_url", "signer_name", "signer_title", "company_name", "researcher_name", ], "sort_order": 40, }, { "key": "duplicate_known", "name_zh": "重复/我们已在处理(不发奖)", "name_en": "Duplicate — already being worked on (no bounty)", "name_ja": "重複・既に対応中(報奨金なし)", "category": const.REPLY_CATEGORY_DUPLICATE, "subject": "Re: your security report to PingCAP [{report_code}]", "body": """Hi {researcher_name}, Thank you very much for taking the time to evaluate our services and share your findings with us. We truly appreciate your efforts in helping us ensure the security of our products. Regarding the issue you reported{duplicate_reference}, we had already been working on this vulnerability prior to your submission. Therefore, we are unable to award a bounty for this specific report. We encourage you to look for vulnerabilities that may impact our core products (such as """ + _CORE_PRODUCTS + """) or our critical domains and services (including """ + _CORE_DOMAINS + """). We would be more than happy to review any additional technical details you can provide for further evaluation. Thank you again for your attention to our security efforts. We greatly value contributions from the security community and look forward to hearing from you again in the future. Warm regards, {signer_name} {signer_title} {company_name}""", "variables": [ "report_code", "duplicate_reference", "signer_name", "signer_title", "company_name", "researcher_name", ], "sort_order": 50, }, { "key": "reward_critical", "name_zh": "确认有效 · 严重档发奖(报金额)", "name_en": "Valid — Critical tier, reward stated", "name_ja": "有効 · 重大ランクの報奨金(金額明記)", "category": const.REPLY_CATEGORY_REWARD, "subject": "Re: your security report to PingCAP [{report_code}]", "body": """Hi {researcher_name}, Thank you for reporting this to us, and for the detail you provided. We have reproduced and confirmed the issue you reported in {affected_system}. We have graded it **{severity_label}** under our published severity ladder. Your reward for this report is **USD {amount_usd}**. What we need from you to pay it: 1. An invoice addressed to the entity below. 2. Nothing else for now — our finance team will contact you directly to arrange the payment method. Please do not send bank details by email. {entity_block} We will confirm here once the payment has been issued. We welcome further review of """ + _CORE_DOMAINS + """ and other TiDB-related products; reports there may qualify for a higher tier. Thank you again for reporting this responsibly. Best regards, {signer_name} {signer_title} {company_name}""", "variables": [ "researcher_name", "report_code", "affected_system", "severity_label", "amount_usd", "entity_block", "signer_name", "signer_title", "company_name", ], "sort_order": 61, }, { "key": "reward_high", "name_zh": "确认有效 · 高危档发奖(报金额)", "name_en": "Valid — High tier, reward stated", "name_ja": "有効 · 高ランクの報奨金(金額明記)", "category": const.REPLY_CATEGORY_REWARD, "subject": "Re: your security report to PingCAP [{report_code}]", "body": """Hi {researcher_name}, Thank you for reporting this to us, and for the detail you provided. We have reproduced and confirmed the issue you reported in {affected_system}. We have graded it **{severity_label}** under our published severity ladder. Your reward for this report is **USD {amount_usd}**. What we need from you to pay it: 1. An invoice addressed to the entity below. 2. Nothing else for now — our finance team will contact you directly to arrange the payment method. Please do not send bank details by email. {entity_block} We will confirm here once the payment has been issued. We welcome further review of """ + _CORE_DOMAINS + """ and other TiDB-related products; reports there may qualify for a higher tier. Thank you again for reporting this responsibly. Best regards, {signer_name} {signer_title} {company_name}""", "variables": [ "researcher_name", "report_code", "affected_system", "severity_label", "amount_usd", "entity_block", "signer_name", "signer_title", "company_name", ], "sort_order": 62, }, { "key": "reward_medium", "name_zh": "确认有效 · 中危档发奖(报金额)", "name_en": "Valid — Medium tier, reward stated", "name_ja": "有効 · 中ランクの報奨金(金額明記)", "category": const.REPLY_CATEGORY_REWARD, "subject": "Re: your security report to PingCAP [{report_code}]", "body": """Hi {researcher_name}, Thank you for reporting this to us, and for the detail you provided. We have reproduced and confirmed the issue you reported in {affected_system}. We have graded it **{severity_label}** under our published severity ladder. Your reward for this report is **USD {amount_usd}**. What we need from you to pay it: 1. An invoice addressed to the entity below. 2. Nothing else for now — our finance team will contact you directly to arrange the payment method. Please do not send bank details by email. {entity_block} We will confirm here once the payment has been issued. We welcome further review of """ + _CORE_DOMAINS + """ and other TiDB-related products; reports there may qualify for a higher tier. Thank you again for reporting this responsibly. Best regards, {signer_name} {signer_title} {company_name}""", "variables": [ "researcher_name", "report_code", "affected_system", "severity_label", "amount_usd", "entity_block", "signer_name", "signer_title", "company_name", ], "sort_order": 63, }, { "key": "reward_low", "name_zh": "确认有效 · 低危档发奖(报金额)", "name_en": "Valid — Low tier, reward stated", "name_ja": "有効 · 低ランクの報奨金(金額明記)", "category": const.REPLY_CATEGORY_REWARD, "subject": "Re: your security report to PingCAP [{report_code}]", "body": """Hi {researcher_name}, Thank you for reporting this to us, and for the detail you provided. We have reproduced and confirmed the issue you reported in {affected_system}. We have graded it **{severity_label}** under our published severity ladder. Your reward for this report is **USD {amount_usd}**. What we need from you to pay it: 1. An invoice addressed to the entity below. 2. Nothing else for now — our finance team will contact you directly to arrange the payment method. Please do not send bank details by email. {entity_block} We will confirm here once the payment has been issued. We welcome further review of """ + _CORE_DOMAINS + """ and other TiDB-related products; reports there may qualify for a higher tier. Thank you again for reporting this responsibly. Best regards, {signer_name} {signer_title} {company_name}""", "variables": [ "researcher_name", "report_code", "affected_system", "severity_label", "amount_usd", "entity_block", "signer_name", "signer_title", "company_name", ], "sort_order": 64, }, { "key": "reward_informational", "name_zh": "确认有效 · 告知档发奖(报金额)", "name_en": "Valid — Informational tier, reward stated", "name_ja": "有効 · 参考情報ランクの報奨金(金額明記)", "category": const.REPLY_CATEGORY_REWARD, "subject": "Re: your security report to PingCAP [{report_code}]", "body": """Hi {researcher_name}, Thank you for reporting this to us, and for the detail you provided. We have reproduced and confirmed the issue you reported in {affected_system}. We have graded it **{severity_label}** under our published severity ladder. Your reward for this report is **USD {amount_usd}**. What we need from you to pay it: 1. An invoice addressed to the entity below. 2. Nothing else for now — our finance team will contact you directly to arrange the payment method. Please do not send bank details by email. {entity_block} We will confirm here once the payment has been issued. We welcome further review of """ + _CORE_DOMAINS + """ and other TiDB-related products; reports there may qualify for a higher tier. Thank you again for reporting this responsibly. Best regards, {signer_name} {signer_title} {company_name}""", "variables": [ "researcher_name", "report_code", "affected_system", "severity_label", "amount_usd", "entity_block", "signer_name", "signer_title", "company_name", ], "sort_order": 65, }, { "key": "payment_sent", "name_zh": "已付款通知", "name_en": "Payment issued", "name_ja": "支払い完了の通知", "category": const.REPLY_CATEGORY_REWARD, "subject": "Re: your security report to PingCAP [{report_code}] — payment issued", "body": """Hi {researcher_name}, The reward of USD {amount_usd} for {report_code} has been issued. If it has not reached you within ten business days, reply to this thread and we will chase it with our finance team. Thank you again for reporting this to us responsibly. Best regards, {signer_name} {signer_title} {company_name}""", "variables": [ "researcher_name", "report_code", "amount_usd", "signer_name", "signer_title", "company_name", ], "sort_order": 70, }, ) TEMPLATE_KEYS: tuple[str, ...] = tuple(t["key"] for t in REPLY_TEMPLATES) #: Which template the reply picker pre-selects for a given triage #: outcome. Purely a UI convenience — the operator can pick any. #: Which reward letter belongs to a graded, confirmed report. Keyed by the #: severity tier, because the letter now STATES the amount and the tier is #: what decides it — one shared "confirmed" letter is how the old template #: ended up asserting "low-impact / open source / low severity" over a #: critical finding. SUGGESTED_TEMPLATE_BY_SEVERITY: dict[str, str] = { "critical": "reward_critical", "high": "reward_high", "medium": "reward_medium", "low": "reward_low", "informational": "reward_informational", } def suggested_template(status: str, severity: str | None) -> str | None: """The letter to pre-select for a report in this state. A confirmed report with a grade gets its tier's letter. A confirmed report with NO grade deliberately falls back to "under evaluation": there is no honest reward letter to send before the tier exists, and the previous behaviour — pre-selecting a reward letter and rendering an empty amount — is how "the reply never mentions the money" happened. """ if status == const.STATUS_CONFIRMED: if severity and severity in SUGGESTED_TEMPLATE_BY_SEVERITY: return SUGGESTED_TEMPLATE_BY_SEVERITY[severity] return "under_evaluation" return SUGGESTED_TEMPLATE_BY_STATUS.get(status) SUGGESTED_TEMPLATE_BY_STATUS: dict[str, str] = { const.STATUS_NEW: "under_evaluation", const.STATUS_AWAITING_OWNER: "under_evaluation", const.STATUS_IN_DISCUSSION: "under_evaluation", const.STATUS_OUT_OF_SCOPE: "out_of_scope_general", const.STATUS_DUPLICATE: "duplicate_known", const.STATUS_FALSE_POSITIVE: "out_of_scope_general", const.STATUS_CLOSED: "thanks_generic", } #: Default signature / entity block. Seeded into ``platform_settings`` so #: the operator edits it in the console rather than in code. The address #: is the one already used on bounty invoices. DEFAULT_SIGNATURE: dict[str, str] = { "signer_name": "", "signer_title": "Security Team", "team_name": "Security Team", "company_name": "PingCAP", "security_policy_url": _POLICY_URL, "entity_block": ( "PingCAP (US), Inc.\n" "440 N Wolfe Rd\n" "Sunnyvale, California 94085\n" "United States" ), }