Files
werkrevisor/docs/prs/2026-10-23-PR#132-draft-review.md
claude-code bcab9fac7d
werkator build succeeded after 00:12
werkator/werkrevisor-statistics build succeeded after 00:37
werkator/release build succeeded after 00:20
werkrevisor 0.61.0: tools/draft-review drafts a review for a human, with a local config and an HTML report (#132)
Co-authored-by: claude-code <claude-code@javagil.de>
2026-10-23 10:15:08 +02:00

110 lines
5.7 KiB
Markdown

# PR#132: tools/draft-review Drafts a Review for a Human, with a Local Config and an HTML Report
Version: minor
> **WARNING:** This document describes only the change applied in this PR.
> It may already be outdated once the next PR is merged.
> Historic PR documentation is not maintained along with new PRs; treat it as a snapshot.
## Related Links
- [PR#129](2026-10-20-PR#129-hs-review-diagrams.md): the diagrams next to the draft.
- [PR#130](2026-10-21-PR#130-hs-review-attach.md): `--attach` posts the checked draft.
## Problem
`hs-review` drafts a review by werkrevisor and Codex for PRs that a human reviews, e.g. on dev.hostsharing.net.
It is a script in `~/bin` of one workstation, without version control and without review,
and it holds the server, the repository, the config and the names of the tokens of one host.
The draft is Markdown; a browser shows it only after a conversion by hand,
and its diagrams are images that open in no size of their own.
## Non-Goals
- No change of the review itself.
## Specification
### Feature: a draft review for a human, from a local config
#### Scenario#132.01: the local config names the host
&hellip; so that the repository holds no server, repository or token name of a user.
- **Given** a local config with server, default repository, werkrevisor config, secrets file and token names
- **When** the human runs `tools/draft-review 343`
- **Then** it reviews PR 343 of the default repository with the read token,
and prints the verdict with its strongest finding and the paths of the report
##### Verified by
- [test_draftreview.SettingsTest.test_the_local_config_names_server_repository_config_and_tokens](../../tests/test_draftreview.py)
- [test_draftreview.ResolveTest.test_a_number_means_a_pr_of_the_default_repository](../../tests/test_draftreview.py)
- [test_draftreview.MainTest.test_a_review_reads_with_the_read_token_and_prints_the_verdict](../../tests/test_draftreview.py)
- [test_draftreview.LinkTest.test_a_link_to_the_tool_finds_the_package_of_the_checkout](../../tests/test_draftreview.py);
red/green: with `abspath` instead of `realpath` the link did not find the package.
#### Scenario#132.02: a PR on another server gets no token
&hellip; so that the tokens of the configured server never go to another one.
- **Given** the local config of one server
- **When** the human runs `tools/draft-review` with the URL of a PR on another server
- **Then** it stops before any request and names the expected form of the URL
##### Verified by
- [test_draftreview.ResolveTest.test_a_pr_on_another_server_is_refused](../../tests/test_draftreview.py)
- [test_draftreview.MainTest.test_a_pr_on_another_server_gets_no_token](../../tests/test_draftreview.py)
#### Scenario#132.03: the report opens in a browser, with diagrams to zoom
&hellip; so that the human reads the draft in a browser and looks at each diagram at full size.
- **Given** a draft with diagrams, and pandoc on the workstation
- **When** `tools/draft-review` has written the draft
- **Then** `report.html` stands next to `report.md`, and a click on a diagram opens its SVG on its own
##### Verified by
- [test_draftreview.HtmlTest.test_the_report_gets_an_html_page_with_clickable_diagrams](../../tests/test_draftreview.py)
- [test_draftreview.HtmlTest.test_without_pandoc_there_is_no_html](../../tests/test_draftreview.py)
#### Scenario#132.04: the page runs no script of the draft
&hellip; so that a PR cannot place a script in a finding that runs when the human opens the report.
- **Given** a draft whose finding quotes `<script>` or a `javascript:` link, as a model may copy it from the PR
- **When** `tools/draft-review` writes `report.html` and the human opens it
- **Then** the script shows as text and runs not, and the page allows no script at all
##### Verified by
- [test_draftreview.HtmlTest.test_the_page_runs_no_script_of_the_draft](../../tests/test_draftreview.py);
red/green with pandoc 3: before the fix `report.html` held the `<script>` of the finding and no policy,
after it the `<script>` is text and the page has `Content-Security-Policy: default-src 'none'; …`.
- [test_draftreview.HtmlTest.test_a_draft_cannot_inject_a_script_with_pandoc](../../tests/test_draftreview.py),
where pandoc is installed; red/green with pandoc 3: with `markdown-raw_html` and pandoc's template,
a YAML block and raw attributes in a finding put 3 scripts into the page, 2 of them into the head before the policy;
`gfm-raw_html` and `commonmark-raw_html` still kept the inline `<script>`;
with `markdown_strict-raw_html+pipe_tables` and the own template none.
## Solution
- `tools/draft-review` and `werkrevisor/draftreview.py` replace `~/bin/hs-review` of one workstation:
they read `~/.config/werkrevisor/draft-review.toml`, resolve a PR number or URL against its server,
read the secrets file, pass the read token, or the write token for `--attach`, to `tools/review-report`,
print the summary line and write `report.html` with pandoc.
- `report.html` is strict Markdown without raw HTML, plus tables (`--from markdown_strict-raw_html+pipe_tables`):
no raw HTML, no YAML metadata block, no raw attribute;
an own template puts a Content Security Policy without scripts first into the head
and takes only the body and our title from pandoc;
a link with `javascript:`, `vbscript:` or `data:` leads to `#blocked-…`, also where a browser ignores the policy.
The Codex reviews of `61b5b80` and `cf1f13c` found the holes.
- `werkrevisor/reviewreport.py` links each diagram to its SVG: `[![name](name)](name)`;
`--attach` points both to the attachment.
- `README.md`, "Draft review": the local config, with example values.
- On the workstation, `~/bin/hs-review` becomes a link to `tools/draft-review`,
and `~/.config/werkrevisor/draft-review.toml` holds the values of dev.hostsharing.net.