From 44cd0e1ecee9b50a4e6b787a065d410be6f66783 Mon Sep 17 00:00:00 2001 From: "Backend (OCTO)" Date: Wed, 17 Jun 2026 23:47:10 +0800 Subject: [PATCH 1/2] docs: add org-wide issue triage policy with 7-day SLA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documents the triage SLA (no issue untriaged > 7 days on octo-server / octo-web), the label taxonomy, priority guide, security-escalation rule, and per-repo triage ownership (Backend → octo-server, Frontend → octo-web, CTO backstop + SecurityEngineer routing). Adds a short pointer from CONTRIBUTING.md. Phase-0 contributor-experience item (OCT-14). Co-Authored-By: Paperclip --- CONTRIBUTING.md | 8 ++++ docs/triage-policy.md | 90 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 docs/triage-policy.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8ed0e3d..7df5d14 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -76,6 +76,14 @@ Use the repository's **Bug Report** issue template. Include: - Expected vs. actual behavior - Environment details (OS, runtime version, etc.) +## Issue Triage + +New issues are labeled `needs-triage` automatically. Maintainers triage them — assign +`type:*` and `priority:*` labels, confirm validity, and route security-sensitive +reports — within **7 days** on the busiest repos. See the +[Issue Triage Policy](docs/triage-policy.md) for the full SLA, priority guide, and +per-repo ownership. + ## Suggesting Features > **Significant features require a Discussion before an Issue.** diff --git a/docs/triage-policy.md b/docs/triage-policy.md new file mode 100644 index 0000000..aca5666 --- /dev/null +++ b/docs/triage-policy.md @@ -0,0 +1,90 @@ +# Issue Triage Policy + +This policy applies to all repositories under the Mininglamp-OSS organization. It +defines how incoming issues are triaged, the service-level agreement (SLA) we hold +ourselves to, and who owns triage for the two busiest repositories +(`octo-server` and `octo-web`). + +## Goal + +Every contributor who files an issue should get a clear, timely signal that it was +seen, understood, and routed. No issue should sit unattended. + +## Triage SLA + +> **No issue stays untriaged for longer than 7 days** on the busiest repos +> (`octo-server`, `octo-web`). Other repos follow the same rule on a best-effort basis. + +An issue is considered **triaged** when all of the following are true: + +1. It has a `type:*` label (`type:bug`, `type:feature`, `type:security`, + `type:chore`, `type:docs`, or `type:refactor`). +2. It has a `priority:*` label (`priority:P0`–`priority:P3`). +3. The `needs-triage` label has been **removed**. +4. If it is security-sensitive, it is labeled `type:security` and escalated to the + CTO for SecurityEngineer scheduling (see [Security-sensitive issues](#security-sensitive-issues)). + +Newly opened issues are auto-labeled `needs-triage`. The triage owner clears that +label as part of triage. + +## What "triage" involves + +For each `needs-triage` issue, the owner: + +- **Confirms reproducibility / validity.** For bug reports, sanity-check the report + (code analysis is enough for an initial pass; deep reproduction can be deferred + with `needs-human-verify`). If more information is needed, apply `needs-more-info` + and ask the reporter. +- **Classifies** with a `type:*` label. +- **Sets priority** with a `priority:*` label (see below). +- **Flags newcomer-friendly work** with `good first issue` where appropriate. +- **Routes security-sensitive issues** to the CTO (see below). +- **Removes** `needs-triage`. + +## Priority guide + +| Label | Meaning | Examples | +|-------|---------|----------| +| `priority:P0` | Critical — drop everything | Active outage, data loss, exploited vulnerability | +| `priority:P1` | High — this sprint | Privilege-escalation risk, regression guard for an auth fix, broken core flow | +| `priority:P2` | Medium — next sprint | Data-consistency edge cases, availability hardening, forensics/audit gaps | +| `priority:P3` | Low — backlog | Minor UX bugs, refactors, misleading docs, ergonomic wins | + +## Security-sensitive issues + +Issues touching authentication, authorization, secrets, audit/forensics, trust +boundaries, or supply chain are **security-sensitive**. + +- Label them `type:security` and set a priority. +- **Escalate to the CTO** for SecurityEngineer scheduling. Do not assign a fix as part + of routine triage. +- **Do not post exploit detail in public comments.** Keep the discussion at the + classification level; detailed analysis goes through the CTO / SecurityEngineer + channel. + +## Triage ownership & rotation + +| Repo | Triage owner | Backstop | +|------|--------------|----------| +| `octo-server` | **Backend** engineer | CTO | +| `octo-web` | **Frontend** engineer | CTO | +| Security-labeled issues (any repo) | **CTO** → SecurityEngineer | — | + +**Cadence:** each owner runs a triage sweep of their repo at least **weekly**, and +whenever a `needs-triage` issue approaches the 7-day line. The CTO is the escalation +point and covers when an owner is unavailable. + +For other repos, the owning engineer for that service triages on a best-effort basis; +unclear ownership is routed to the CTO. + +## Checking the backlog + +List untriaged issues for a repo: + +```bash +gh issue list --repo Mininglamp-OSS/ --label needs-triage --state open \ + --json number,title,createdAt +``` + +Anything with a `createdAt` older than 7 days is an SLA breach and should be cleared +immediately. From 82e90908b49e969548ff98dfc2313937ac2328e6 Mon Sep 17 00:00:00 2001 From: "Backend (OCTO)" Date: Thu, 18 Jun 2026 00:17:23 +0800 Subject: [PATCH 2/2] docs(triage): reconcile with SECURITY.md + address review feedback Addresses PR #75 review (yujiawei CHANGES_REQUESTED + Octo-Q P2s + CTO ask): - P1: vulnerabilities now explicitly follow SECURITY.md private disclosure, not public triage. Public type:security scoped to non-vuln security work (hardening/audit/already-disclosed). Adds containment steps for a vuln that lands publicly and links SECURITY.md. - Redaction of pre-existing public issues called out as in-scope for the triage owner (per CTO; octo-web #330 precedent). - Security backstop: CEO if CTO unreachable on a P0/P1 nearing the line. Documents CTO-routes / SecurityEngineer-owns-once-staffed (no interim gap). - Ownership uses queryable team handles (server-/web-/maintainers). - SLA scope split into hard (octo-server/octo-web) vs best-effort vs exempt (.github meta-repo). Defines "approaches the 7-day line" = age >= 5 days. - Reopened/transferred/imported issues routed back through triage. - Priority guide anchored with real precedents (#366/#394/#367/#397). - CONTRIBUTING pointer softened to "busiest repos" + SECURITY.md note. Co-Authored-By: Paperclip --- CONTRIBUTING.md | 7 +-- docs/triage-policy.md | 119 +++++++++++++++++++++++++++++------------- 2 files changed, 86 insertions(+), 40 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7df5d14..c67a57c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -79,10 +79,11 @@ Use the repository's **Bug Report** issue template. Include: ## Issue Triage New issues are labeled `needs-triage` automatically. Maintainers triage them — assign -`type:*` and `priority:*` labels, confirm validity, and route security-sensitive -reports — within **7 days** on the busiest repos. See the +`type:*` and `priority:*` labels, confirm validity, and route security reports — within +**7 days** on the busiest repos (`octo-server`, `octo-web`). Suspected vulnerabilities +follow [SECURITY.md](SECURITY.md) (private disclosure), not public triage. See the [Issue Triage Policy](docs/triage-policy.md) for the full SLA, priority guide, and -per-repo ownership. +ownership for the busiest repos. ## Suggesting Features diff --git a/docs/triage-policy.md b/docs/triage-policy.md index aca5666..11ae80c 100644 --- a/docs/triage-policy.md +++ b/docs/triage-policy.md @@ -1,31 +1,48 @@ # Issue Triage Policy -This policy applies to all repositories under the Mininglamp-OSS organization. It -defines how incoming issues are triaged, the service-level agreement (SLA) we hold -ourselves to, and who owns triage for the two busiest repositories -(`octo-server` and `octo-web`). +This policy describes how incoming issues are triaged across the Mininglamp-OSS +organization. The **hard 7-day SLA** below binds the two busiest repositories +(`octo-server` and `octo-web`); other repositories follow it as a best-effort target. + +> **Vulnerabilities are out of scope for public triage.** Suspected or undisclosed +> security vulnerabilities follow [`SECURITY.md`](../SECURITY.md) — private report to +> **security@mininglamp.com** under coordinated disclosure — **not** the public issue +> workflow described here. See [Security-sensitive issues](#security-sensitive-issues). ## Goal Every contributor who files an issue should get a clear, timely signal that it was seen, understood, and routed. No issue should sit unattended. -## Triage SLA +## Scope of the SLA -> **No issue stays untriaged for longer than 7 days** on the busiest repos -> (`octo-server`, `octo-web`). Other repos follow the same rule on a best-effort basis. +| Tier | Repos | Commitment | +|------|-------|------------| +| **Hard SLA** | `octo-server`, `octo-web` | No issue stays untriaged longer than **7 days** | +| **Best-effort target** | All other public repos | Same intent, no hard guarantee | +| **Exempt** | Meta-repos with no external issue intake (e.g. this `.github` repo) | Not subject to the SLA | + +## Triage SLA -An issue is considered **triaged** when all of the following are true: +On the hard-SLA repos, **no issue stays untriaged for longer than 7 days.** An issue +is considered **triaged** when all of the following are true: 1. It has a `type:*` label (`type:bug`, `type:feature`, `type:security`, `type:chore`, `type:docs`, or `type:refactor`). 2. It has a `priority:*` label (`priority:P0`–`priority:P3`). 3. The `needs-triage` label has been **removed**. -4. If it is security-sensitive, it is labeled `type:security` and escalated to the - CTO for SecurityEngineer scheduling (see [Security-sensitive issues](#security-sensitive-issues)). +4. If it is security-related, it has been handled per + [Security-sensitive issues](#security-sensitive-issues) (vulnerabilities routed to + private disclosure; non-vulnerability security work labeled `type:security`). -Newly opened issues are auto-labeled `needs-triage`. The triage owner clears that -label as part of triage. +Newly opened, non-bot issues are auto-labeled `needs-triage` by the +`issue-welcome.yml` reusable workflow (each repo opts in via its own caller). The +triage owner clears that label as part of triage. + +**Re-entry paths.** Auto-labeling only covers *newly opened* issues. **Reopened, +transferred, or imported issues must be routed back through triage** — re-apply +`needs-triage` so they reappear in the backlog. Note the backlog query below keys on +`createdAt` (original creation), so reopened/stale items need a deliberate manual pass. ## What "triage" involves @@ -38,44 +55,71 @@ For each `needs-triage` issue, the owner: - **Classifies** with a `type:*` label. - **Sets priority** with a `priority:*` label (see below). - **Flags newcomer-friendly work** with `good first issue` where appropriate. -- **Routes security-sensitive issues** to the CTO (see below). +- **Handles security-related reports** per the security section below. - **Removes** `needs-triage`. ## Priority guide -| Label | Meaning | Examples | -|-------|---------|----------| -| `priority:P0` | Critical — drop everything | Active outage, data loss, exploited vulnerability | -| `priority:P1` | High — this sprint | Privilege-escalation risk, regression guard for an auth fix, broken core flow | -| `priority:P2` | Medium — next sprint | Data-consistency edge cases, availability hardening, forensics/audit gaps | -| `priority:P3` | Low — backlog | Minor UX bugs, refactors, misleading docs, ergonomic wins | +| Label | Meaning | Real precedent | +|-------|---------|----------------| +| `priority:P0` | Critical — drop everything | Active outage, data loss, or an exploited vulnerability | +| `priority:P1` | High — this sprint | `octo-server #366` — no central authz layer, so a forgotten role check on a `/v1/manager` route is a silent privilege escalation | +| `priority:P2` | Medium — next sprint | `octo-server #394` (compensating delete leaves orphan group rows); `octo-server #367` (no admin-action audit trail) | +| `priority:P3` | Low — backlog | `octo-web #397` — contact search box doesn't auto-close (minor UX) | -## Security-sensitive issues +Borderline P1-vs-P2 calls lean on blast radius and exploitability: a latent risk that +*guards* an auth fix from regression (e.g. `octo-server #353`) is P1; a consistency or +forensics gap with no active user impact is P2. -Issues touching authentication, authorization, secrets, audit/forensics, trust -boundaries, or supply chain are **security-sensitive**. +## Security-sensitive issues -- Label them `type:security` and set a priority. -- **Escalate to the CTO** for SecurityEngineer scheduling. Do not assign a fix as part - of routine triage. -- **Do not post exploit detail in public comments.** Keep the discussion at the - classification level; detailed analysis goes through the CTO / SecurityEngineer - channel. +**First, the hard distinction:** + +- **Suspected or undisclosed vulnerabilities do _not_ go through public triage.** They + follow [`SECURITY.md`](../SECURITY.md): a private report to **security@mininglamp.com** + under coordinated disclosure, or a + [GitHub Private Vulnerability Advisory](https://docs.github.com/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability). + Do **not** apply a public `type:security` label to an unresolved, undisclosed vuln — + a public, searchable `type:security` signal on a live vuln is itself a disclosure. +- **Public `type:security` is for non-vulnerability security work**: hardening, + authorization/architecture follow-ups, audit/forensics/process gaps, and + already-disclosed or already-fixed items. + +**Containment — if a vulnerability lands as a public issue (new _or_ pre-existing):** + +1. **Minimize/redact the issue body** — remove repro steps, PoC, and weaponization + detail. Redacting *pre-existing* public issues is **in-scope for the triage owner**, + not just new reports. (Precedent: `octo-web #330`'s body was redacted to the + structural finding + defensive fix; full detail moved to the internal tracker.) +2. **Redirect the reporter** to private reporting per `SECURITY.md`. +3. **Consider converting** the issue to a GitHub Private Vulnerability Advisory. +4. Only then classify any residual *structural* finding with `type:security`, or close + it in favor of the private track. + +- **Never post exploit detail in public comments.** +- **Escalation:** route security-labeled issues to the **CTO** for SecurityEngineer + scheduling. The CTO routes; a SecurityEngineer owns implementation once staffed. In + the interim the **CTO owns security-labeled triage directly** and delegates + implementation slices under security review — there is no coverage gap. +- **Backstop:** if the CTO is unreachable and a P0/P1 security item is approaching the + 7-day line, escalate to the **CEO**. ## Triage ownership & rotation +Ownership maps to a queryable GitHub team handle so accountability does not diffuse: + | Repo | Triage owner | Backstop | |------|--------------|----------| -| `octo-server` | **Backend** engineer | CTO | -| `octo-web` | **Frontend** engineer | CTO | -| Security-labeled issues (any repo) | **CTO** → SecurityEngineer | — | +| `octo-server` | [`@Mininglamp-OSS/server-maintainers`](https://github.com/orgs/Mininglamp-OSS/teams/server-maintainers) (Backend) | [`@Mininglamp-OSS/maintainers`](https://github.com/orgs/Mininglamp-OSS/teams/maintainers) / CTO | +| `octo-web` | [`@Mininglamp-OSS/web-maintainers`](https://github.com/orgs/Mininglamp-OSS/teams/web-maintainers) (Frontend) | [`@Mininglamp-OSS/maintainers`](https://github.com/orgs/Mininglamp-OSS/teams/maintainers) / CTO | +| Security-labeled (any repo) | CTO → SecurityEngineer (once staffed) | CEO, if CTO unreachable | -**Cadence:** each owner runs a triage sweep of their repo at least **weekly**, and -whenever a `needs-triage` issue approaches the 7-day line. The CTO is the escalation -point and covers when an owner is unavailable. +**Cadence:** each owner runs a triage sweep at least **weekly**. An issue *approaches +the 7-day line* once its open `needs-triage` age reaches **5 days** — the owner clears +or escalates it before day 7. If an owner misses the line, the backstop is woken. -For other repos, the owning engineer for that service triages on a best-effort basis; -unclear ownership is routed to the CTO. +For repos outside the hard-SLA set, the owning team triages on a best-effort basis; +unclear ownership routes to `@Mininglamp-OSS/maintainers`. ## Checking the backlog @@ -87,4 +131,5 @@ gh issue list --repo Mininglamp-OSS/ --label needs-triage --state open \ ``` Anything with a `createdAt` older than 7 days is an SLA breach and should be cleared -immediately. +immediately. Because the query keys on `createdAt`, also scan recently **reopened** +issues — re-apply `needs-triage` to any that need a fresh pass.