diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 3c2fcc4..3acc383 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -20,3 +20,8 @@ jobs: run: | ./mdbook build ./mdbook test + + - name: Confirm that the checklist is up to date + run: | + ./export_checklist.py + git diff --exit-code diff --git a/checklist.md b/checklist.md new file mode 100644 index 0000000..c01f2f0 --- /dev/null +++ b/checklist.md @@ -0,0 +1,77 @@ +# Checklist + +This checklist summarizes the recommendations in all the chapters. +The main purpose of this page is to have a markdown checklist that +we can copy into an issue for internal due diligence processes. It +is not part of the book itself. Rebuild with `export_checklist.py`. + +## P0 + +#### Software development best practices + - [ ] [Respect licenses of upstream software.](https://handbook.chorus.one/node-software/development-practices.html#respect-licenses) + - [ ] [Break down changes into logical parts and write a clear commit message for each change.](https://handbook.chorus.one/node-software/development-practices.html#good-commits) + - [ ] [Use comments to clarify non-obvious code.](https://handbook.chorus.one/node-software/development-practices.html#use-comments) + +#### Open source software + - [ ] [Be transparent about the provenance of your source code.](https://handbook.chorus.one/node-software/open-source.html#provenance-transparency) + +## P1 + +#### Build process + - [ ] [Ensure your software can be built on a stock Ubuntu LTS installation.](https://handbook.chorus.one/node-software/build-process.html#builds-on-ubuntu) + - [ ] [Don’t require Docker as part of your build process.](https://handbook.chorus.one/node-software/build-process.html#no-docker) + - [ ] [Don’t fetch untrusted binaries from the Internet as part of your build scripts.](https://handbook.chorus.one/node-software/build-process.html#no-fetch-untrusted-binaries) + - [ ] [Include a `rust-toolchain.toml` file in your repository.](https://handbook.chorus.one/node-software/build-process.html#use-rust-toolchain) + +#### Software development best practices + - [ ] [Write automated tests that are included in the repository.](https://handbook.chorus.one/node-software/development-practices.html#automated-tests) + - [ ] [Have a code review process.](https://handbook.chorus.one/node-software/development-practices.html#code-review) + - [ ] [Write clear pull request, merge request, or changelist descriptions.](https://handbook.chorus.one/node-software/development-practices.html#write-clear-pr-descriptions) + - [ ] [Set up continuous integration.](https://handbook.chorus.one/node-software/development-practices.html#continuous-integration) + +#### Monitoring + - [ ] [Expose Prometheus metrics.](https://handbook.chorus.one/node-software/monitoring.html#expose-prometheus-metrics) + - [ ] [Expose metrics privately.](https://handbook.chorus.one/node-software/monitoring.html#expose-metrics-privately) + +#### Open source software + - [ ] [Release the project under an open source license.](https://handbook.chorus.one/node-software/open-source.html#publish-open-source) + +#### Release engineering + - [ ] [Publish the source code in a public Git repository.](https://handbook.chorus.one/node-software/release-engineering.html#public-git-repo) + - [ ] [Mark releases with a Git tag.](https://handbook.chorus.one/node-software/release-engineering.html#use-git-tags) + - [ ] [Use _annotated_ Git tags.](https://handbook.chorus.one/node-software/release-engineering.html#use-annotated-tags) + - [ ] [Do not — never ever — re-tag.](https://handbook.chorus.one/node-software/release-engineering.html#no-retagging) + - [ ] [When using submodules, use `https` transport urls.](https://handbook.chorus.one/node-software/release-engineering.html#submodule-use-https-transport) + +## P2 + +#### Software development best practices + - [ ] [Write fuzz tests for code that deals with user input (network or user data).](https://handbook.chorus.one/node-software/development-practices.html#fuzz-tests) + - [ ] [Set up a bug bounty program.](https://handbook.chorus.one/node-software/development-practices.html#bug-bounty-program) + - [ ] [Set up a responsible disclosure policy.](https://handbook.chorus.one/node-software/development-practices.html#responsible-disclosure-policy) + +#### Monitoring + - [ ] [Ensure telemetry can be disabled.](https://handbook.chorus.one/node-software/monitoring.html#telemetry-can-be-disabled) + +#### Open source software + - [ ] [Ensure that node operators can build security fixes from source.](https://handbook.chorus.one/node-software/open-source.html#security-fixes-source) + +#### Release engineering + - [ ] [Publish metadata about the release in an easily discoverable location.](https://handbook.chorus.one/node-software/release-engineering.html#publish-release-metadata) + - [ ] [Use the same number of parts in every version number.](https://handbook.chorus.one/node-software/release-engineering.html#version-number-parts) + - [ ] [Use consistent suffixes to mark pre-release versions.](https://handbook.chorus.one/node-software/release-engineering.html#consistent-suffixes) + - [ ] [Publish a release at least one week before an update deadline.](https://handbook.chorus.one/node-software/release-engineering.html#publish-headroom) + - [ ] [Do not release on Fridays.](https://handbook.chorus.one/node-software/release-engineering.html#no-release-friday) + - [ ] [Do not release just before a holiday.](https://handbook.chorus.one/node-software/release-engineering.html#no-release-holiday) + +## P3 + +#### Monitoring + - [ ] [Respect Prometheus metric and label naming standards.](https://handbook.chorus.one/node-software/monitoring.html#respect-prometheus-standards) + +#### Open source software + - [ ] [Build in the open.](https://handbook.chorus.one/node-software/open-source.html#build-in-the-open) + +#### Release engineering + - [ ] [Keep a changelog.](https://handbook.chorus.one/node-software/release-engineering.html#keep-a-changelog) + diff --git a/export_checklist.py b/export_checklist.py new file mode 100755 index 0000000..96db98b --- /dev/null +++ b/export_checklist.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# Copyright 2024 Chorus One, licensed CC BY-NC-SA 4.0. +""" +export_checklist.py -- Export all recommendations as Markdown checklist. +""" + +from collections import defaultdict +from typing import Dict, Iterable, List, NamedTuple, Optional + +import textwrap +import os +import sys + + +class Recommendation(NamedTuple): + chapter: str + file: str + id: str + priority: int + title: str + + def get_url(self) -> str: + slug = self.file.removeprefix("src/").removesuffix(".md") + return f"https://handbook.chorus.one/{slug}.html#{self.id}" + + +def list_md_files() -> Iterable[str]: + for root, dirs, files in os.walk("src"): + for file in files: + if file.endswith(".md"): + yield os.path.join(root, file) + + +def list_recommendations(fname: str) -> Iterable[Recommendation]: + chapter: Optional[str] = None + + with open(fname, "r", encoding="utf-8") as f: + for i, line in enumerate(f): + if line.startswith("# "): + chapter = line[2:].strip() + + if line.startswith("#### "): + try: + # Recommendation lines are of the form `#### Title {.prio # #id}\n". + title = line.removeprefix("#### ") + title, meta = title.rsplit("{", maxsplit=1) + meta = meta.strip().removesuffix("}") + prio_str, id_str = meta.split(" ", maxsplit=1) + assert prio_str.startswith( + ".p" + ), "Recommendation line must end in `{.pN #id}`." + assert id_str.startswith( + "#" + ), "Recommendation line must end in `{.pN #id}`." + assert chapter is not None, "Must have # chapter title before ####." + + yield Recommendation( + chapter=chapter, + file=fname, + id=id_str[1:], + priority=int(prio_str[2:]), + title=title.strip(), + ) + + except Exception as exc: + print(f"Error in {fname} at line {i + 1}:", file=sys.stderr) + print(f"{i + 1} | {line}", end="", file=sys.stderr) + print(f"Error: {exc}", file=sys.stderr) + sys.exit(1) + + +def main() -> None: + by_priority: Dict[int, List[Recommendation]] = defaultdict(lambda: []) + out_fname = "checklist.md" + + for fname in sorted(list_md_files()): + # In the intro we list the priority categories, they are not themselves + # recommendations. + if fname == "src/node-software/intro.md": + continue + + for rec in list_recommendations(fname): + by_priority[rec.priority].append(rec) + + with open(out_fname, "w", encoding="utf-8") as f: + f.write(textwrap.dedent( + """ + # Checklist + + This checklist summarizes the recommendations in all the chapters. + The main purpose of this page is to have a markdown checklist that + we can copy into an issue for internal due diligence processes. It + is not part of the book itself. Rebuild with `export_checklist.py`. + """ + ).strip()) + f.write("\n\n") + + for priority, recommendations in sorted(by_priority.items()): + f.write(f"## P{priority}\n") + + chapter = "" + for rec in recommendations: + if rec.chapter != chapter: + f.write(f"\n#### {rec.chapter}\n") + chapter = rec.chapter + + f.write(f" - [ ] [{rec.title}]({rec.get_url()})\n") + + f.write("\n") + + print(f"Checklist written to {out_fname}.") + + +if __name__ == "__main__": + main() diff --git a/src/node-software/build-process.md b/src/node-software/build-process.md index 423b306..1a641d0 100644 --- a/src/node-software/build-process.md +++ b/src/node-software/build-process.md @@ -88,7 +88,7 @@ that download from official registries are of course fine. > This section is a work in progress. ## Rust recommendations