|
34 | 34 | # A surface is live by where it is, never by what else its text happens to |
35 | 35 | # contain: it hands an address to a user, a host or another tool at run time, |
36 | 36 | # or it is the command someone copies. |
37 | | -LIVE_SURFACE_PREFIXES = ("loopx/", "scripts/", ".github/workflows/", "packages/") |
| 37 | +# `.github/` is whole, not just its workflows: GitHub renders |
| 38 | +# `ISSUE_TEMPLATE/config.yml` as the contact links on the new-issue page, and |
| 39 | +# `SECURITY.md`, `SUPPORT.md`, `GOVERNANCE.md` and `PULL_REQUEST_TEMPLATE.md` |
| 40 | +# each hand an address to the person reading them. |
| 41 | +LIVE_SURFACE_PREFIXES = ("loopx/", "scripts/", ".github/", "packages/") |
38 | 42 | # A built bundle is regenerated, not edited, so its baked-in address is fixed by |
39 | 43 | # the release that rebuilds it. This is the tracked-build-output cost #4677 names. |
40 | 44 | GENERATED_ASSET_PREFIXES = ("loopx/web/chat/assets/",) |
|
49 | 53 | "loopx/capabilities/issue_fix/README.md": frozenset({"pull"}), |
50 | 54 | "loopx/capabilities/issue_fix/README.zh-CN.md": frozenset({"pull"}), |
51 | 55 | "packages/loopx-codex-provider-routing/RUNBOOK.md": frozenset({"pull"}), |
| 56 | + # Governance records where the project started and which issue settled a |
| 57 | + # roster change: both name the address the event happened under, while the |
| 58 | + # ruleset link in the same file is called live and stays under review. |
| 59 | + ".github/GOVERNANCE.md": frozenset({"commit", "issue"}), |
52 | 60 | } |
53 | 61 | DISAMBIGUATION_TERMS_SOURCE = ( |
54 | 62 | "packages/loopx-community-discussion/src/loopx_community_discussion/normalize.py" |
@@ -87,14 +95,13 @@ def _address_use(raw_path: str) -> str: |
87 | 95 | ) |
88 | 96 |
|
89 | 97 |
|
90 | | -# A use is either a live pointer this project must own or a dated citation that |
91 | | -# may keep the address the event happened under. |
92 | | -LIVE_ADDRESS_USES = frozenset( |
93 | | - {"repository", "issue_form", "discussion", "release_asset", "main_pointer", "branch"}) |
94 | | - |
95 | | - |
96 | 98 | def stale_address_uses(name: str, text: str) -> list[str]: |
97 | | - """Return the old-address uses in a live surface that were never reviewed.""" |
| 99 | + """Return the old-address uses in ``name`` that were never reviewed per use. |
| 100 | +
|
| 101 | + Every classified use is an offender until a path-and-use exception reviews it, |
| 102 | + so widening which files are live cannot quietly reclassify a dated citation as |
| 103 | + safe: it has to be judged and named here. |
| 104 | + """ |
98 | 105 |
|
99 | 106 | tolerated = REVIEWED_ADDRESS_EXCEPTIONS.get(name, frozenset()) |
100 | 107 | return [ |
@@ -248,6 +255,25 @@ def _validate_stale_address_classifier() -> None: |
248 | 255 | "main_pointer" |
249 | 256 | ]: |
250 | 257 | raise AssertionError("a documentation pointer must be named as a live address") |
| 258 | + advisory = "https://github.com/huangruiteng/loopx/security/advisories/new\n" |
| 259 | + if stale_address_uses(".github/SECURITY.md", advisory) != ["security"]: |
| 260 | + raise AssertionError( |
| 261 | + "the private-vulnerability-reporting entry is how a reporter reaches this " |
| 262 | + "project, so it must be named as a live address rather than a citation" |
| 263 | + ) |
| 264 | + if not _is_live_surface(".github/ISSUE_TEMPLATE/config.yml"): |
| 265 | + raise AssertionError( |
| 266 | + "GitHub renders ISSUE_TEMPLATE/config.yml as the contact links on its own " |
| 267 | + "new-issue page, so it is a live surface" |
| 268 | + ) |
| 269 | + if stale_address_uses( |
| 270 | + ".github/GOVERNANCE.md", |
| 271 | + "https://github.com/huangruiteng/loopx/commit/7dcdc9dc79226d157ba57d3e8ff4bae664f020c1\n", |
| 272 | + ): |
| 273 | + raise AssertionError( |
| 274 | + "widening .github/ must not turn a dated history citation into an " |
| 275 | + "offender: the commit a project started under keeps that address" |
| 276 | + ) |
251 | 277 | if _is_live_surface("loopx/web/chat/assets/index-abc123.js"): |
252 | 278 | raise AssertionError( |
253 | 279 | "a generated bundle is outside the guard: its address is fixed by the " |
|
0 commit comments