Check the plan before filing into it, keep filed items in order, name the filer's tests in the gate, and record the merge over a worse ruling
This commit is contained in:
@@ -1208,13 +1208,14 @@ docker compose run --rm --user root --entrypoint chown test -R "$(id -u):$(id -g
|
||||
```
|
||||
|
||||
Every pull request runs `docker build .` against both the latest and the lowest
|
||||
supported Go, and must pass before it can be merged — unless it changes none of
|
||||
the files the build and its tests read, nor the workflow itself, in which case
|
||||
it's skipped. That build runs vet, complexity, the format check, the Go tests and the
|
||||
release tooling's tests; the rest of the gate is the changelog check, which CI runs
|
||||
against the PR base, and the package-repository checks below. Run `docker build .`
|
||||
locally before pushing. The lowest Go builds the `portable` stage, which skips the format
|
||||
check and the release tooling's tests:
|
||||
supported Go, and must pass before it can be merged — unless it changes none of the
|
||||
files the build and its tests read, nor the workflow itself, in which case it's skipped.
|
||||
That build runs vet, complexity, the format check, the Go tests, the release tooling's
|
||||
tests and the vulnerability filer's tests, which file an item into `todo.md` itself, so
|
||||
a change to the plan's shape can fail it; the rest of the gate is the changelog check,
|
||||
which CI runs against the PR base, and the package-repository checks below. Run `docker
|
||||
build .` locally before pushing. The lowest Go builds the `portable` stage, which skips
|
||||
the format check and both Python test suites:
|
||||
|
||||
```sh
|
||||
docker build . # latest
|
||||
|
||||
+3
-1
@@ -1007,4 +1007,6 @@ plan; a test files one into the repository's own `todo.md`. When the next releas
|
||||
`todo.md` names no version for it, so the item lands in the release after; the maintainer
|
||||
moves it. Where no Go version fixes a vulnerability yet, govulncheck has no ignore list: the
|
||||
maintainer drops the job from the release's `needs` until one does, and records why here.
|
||||
Valid while the binaries are built from the gate's Go version.
|
||||
The paired ruling against f90b4d6 found the project reads worse for it: the gate now reads
|
||||
`todo.md`, and a release waits on vuln.go.dev. The maintainer merged it anyway, as the cost
|
||||
of filing into the plan. Valid while the binaries are built from the gate's Go version.
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
"""File each module's known vulnerabilities as one security item atop todo.md's next release.
|
||||
|
||||
Usage: file_vulnerabilities.py <govulncheck -format json report> <todo.md>
|
||||
Exits 1 while any vulnerability is known, filed now or before, and 0 on a clean report.
|
||||
Exits 1 while any vulnerability is known, filed now or before, 0 on a clean report, and 2 on
|
||||
a todo.md it cannot read.
|
||||
|
||||
todo.md's `Next ID = N` gives the item's ID, and the release of the plan's top row, the next
|
||||
release, gives its release. Its Score is 0.0 until rank_todo.py, which CI cannot run, scores
|
||||
@@ -21,8 +22,9 @@ import re
|
||||
import sys
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
ROW = re.compile(r"^\| (\d+) \| ([^|]+?) \| [^|]*\| \*\*", re.M)
|
||||
ROW = re.compile(r"^\| (?P<id>\d+) \| (?P<release>[^|]+?) \| [^|]*\| \*\*", re.M)
|
||||
NEXT_ID = re.compile(r"`Next ID = (\d+)`")
|
||||
DETAILS = "## Details\n\n"
|
||||
SCORES = {"R": 1, "S": 1, "C": 1, "A": 8, "G": 8}
|
||||
GOAL = "1.1"
|
||||
|
||||
@@ -100,20 +102,30 @@ def detail(module: Module) -> str:
|
||||
|
||||
def file_items(modules: list[Module], todo: str) -> tuple[str, list[int]]:
|
||||
"""Return todo.md with an item for each module whose vulnerabilities it does not yet name, and the items' IDs."""
|
||||
first = ROW.search(todo)
|
||||
if first is None:
|
||||
raise ValueError("todo.md has no item to take the next release from")
|
||||
if NEXT_ID.search(todo) is None:
|
||||
raise ValueError("todo.md has no `Next ID = N` line to number the item by")
|
||||
if DETAILS not in todo:
|
||||
raise ValueError(f"todo.md has no {DETAILS.strip()!r} heading to put the item's detail under")
|
||||
release, rows_at = first.group("release"), first.start()
|
||||
details_at = todo.index(DETAILS) + len(DETAILS)
|
||||
filed = []
|
||||
for module in modules:
|
||||
if all(osv in todo for osv in module.osvs):
|
||||
continue
|
||||
first = ROW.search(todo)
|
||||
if first is None:
|
||||
raise ValueError("todo.md has no item to take the next release from")
|
||||
next_id = int(NEXT_ID.search(todo).group(1))
|
||||
line = tagline(module)
|
||||
scores = " | ".join(str(SCORES[k]) for k in "RSCAG")
|
||||
row = f"| {next_id} | {first.group(2)} | security | **{line}** | {scores} | {GOAL} | 0.0 |\n"
|
||||
todo = todo[: first.start()] + row + todo[first.start() :]
|
||||
todo = todo.replace(f"`Next ID = {next_id}`", f"`Next ID = {next_id + 1}`", 1)
|
||||
todo = todo.replace("## Details\n\n", f"## Details\n\n### {next_id}. {line}\n\n{detail(module)}\n", 1)
|
||||
row = f"| {next_id} | {release} | security | **{line}** | {scores} | {GOAL} | 0.0 |\n"
|
||||
text = f"### {next_id}. {line}\n\n{detail(module)}\n"
|
||||
todo = todo[:rows_at] + row + todo[rows_at:]
|
||||
rows_at += len(row)
|
||||
details_at += len(row)
|
||||
todo = todo[:details_at] + text + todo[details_at:]
|
||||
details_at += len(text)
|
||||
todo = NEXT_ID.sub(f"`Next ID = {next_id + 1}`", todo, count=1)
|
||||
filed.append(next_id)
|
||||
return todo, filed
|
||||
|
||||
@@ -128,7 +140,11 @@ def main(argv: list[str]) -> int:
|
||||
count = sum(len(m.osvs) for m in modules)
|
||||
known = f"{count} known {'vulnerability' if count == 1 else 'vulnerabilities'}"
|
||||
with open(todo_path, encoding="utf-8") as f:
|
||||
todo, filed = file_items(modules, f.read())
|
||||
try:
|
||||
todo, filed = file_items(modules, f.read())
|
||||
except ValueError as err:
|
||||
print(err, file=sys.stderr)
|
||||
return 2
|
||||
if not filed:
|
||||
print(f"{known}, already planned in todo.md.")
|
||||
return 1
|
||||
|
||||
Reference in New Issue
Block a user