docs: public issue form and moderation
- commit
- e687d9cb37df6ea22c6f33f43d2bf9344322661f
- author
- brice · · 2026-10-19 07:42 UTC
- parent
- cce8cfa
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
3 files · +17 -3
M docs/cli.md +1 -1
| @@ -84,7 +84,7 @@ ermite version # client and server versions | |||
| 84 | 84 | ermite completion bash|zsh|fish | |
| 85 | 85 | ``` | |
| 86 | 86 | ||
| 87 | - | Issues need a server with the `issues` feature and `ermite repo edit <repo> --issues owner`; they are written with the `issue:write` scope. See [Issues](issues.md). | |
| 87 | + | Issues need a server with the `issues` feature and `ermite repo edit <repo> --issues owner` (or `--issues public`, which also opens a moderated form to visitors of a public repository); they are written with the `issue:write` scope. See [Issues](issues.md). | |
| 88 | 88 | ||
| 89 | 89 | ## Output | |
| 90 | 90 | ||
| @@ -84,7 +84,7 @@ ermite version # client and server versions | |||||
| 84 | ermite completion bash|zsh|fish | 84 | ermite completion bash|zsh|fish | ||
| 85 | ``` | 85 | ``` | ||
| 86 | 86 | ||||
| 87 | - | Issues need a server with the `issues` feature and `ermite repo edit <repo> --issues owner`; they are written with the `issue:write` scope. See [Issues](issues.md). | 87 | + | Issues need a server with the `issues` feature and `ermite repo edit <repo> --issues owner` (or `--issues public`, which also opens a moderated form to visitors of a public repository); they are written with the `issue:write` scope. See [Issues](issues.md). |
| 88 | 88 | ||||
| 89 | ## Output | 89 | ## Output | ||
| 90 | 90 | ||||
M docs/issues.md +15 -1
| @@ -20,7 +20,7 @@ All commands take `--json`. `--body -` and `--body-file -` read standard input. | |||
| 20 | 20 | ||
| 21 | 21 | - `off` (default): issues are disabled. | |
| 22 | 22 | - `owner`: the owner and tokens with `issue:write` write issues. | |
| 23 | - | - `public`: the anonymous moderated form; not available yet, the server refuses it. | |
| 23 | + | - `public`: anyone may propose an issue through a moderated form (see [Public form and moderation](#public-form-and-moderation)). The repository must be public too. | |
| 24 | 24 | ||
| 25 | 25 | ## Who can write | |
| 26 | 26 | ||
| @@ -39,3 +39,17 @@ Merge requests and issues of a repository draw `#n` from one sequence, so a numb | |||
| 39 | 39 | The signed-in owner has an Inbox at `/-/inbox`, reached from the **Inbox** button at the top left of the home page, which shows the number of open items. It lists the open merge requests and the open issues of every repository, most recently updated first. The counters at the top (`N merge requests · M issues`) always count everything; `?repo=<name>` restricts the two lists to one repository, and the repository links under the counters set it. Repositories with issues off contribute no issues. | |
| 40 | 40 | ||
| 41 | 41 | The page updates live: merge request and issue events of any repository refresh the counters and the lists. Anyone who is not the signed-in owner, including a token, gets the same 404 as for an unknown page, and the same answer for the `owner` event stream it follows. | |
| 42 | + | ||
| 43 | + | ## Public form and moderation | |
| 44 | + | ||
| 45 | + | With `issues` set to `public` on a public repository, a visitor who is not signed in finds a **New issue** button on the Issues tab, which opens `/<repo>/issues/new`. The form needs JavaScript: the page solves a short proof of work in a worker while the visitor writes (a second or so; harder after many recent submissions), and the button stays disabled until it is done and a few seconds have passed. Without JavaScript the form stays hidden and the page says why. A repository that is private, or whose mode is `off` or `owner`, has no such page: it answers the same 404 as an unknown one. | |
| 46 | + | ||
| 47 | + | Limits: a title of at most 120 characters, a description of at most 10,000, an optional name of at most 40 (not verified). Each network may submit 3 issues per hour and 10 per day. At most 200 submissions await moderation; beyond that the form says submissions are paused. A submission never appears on its own: it is stored as pending and shows no id to the visitor. | |
| 48 | + | ||
| 49 | + | The owner moderates in the Inbox, in the first section, **Awaiting moderation**, whose count is in the counters row. Each submission shows its repository, age, name (or "anonymous"), title and the start of the description, as plain text, with three buttons: **Approve** opens it as the next issue of the repository (numbers are shared with merge requests), **Reject** deletes it, **Reject and ban** deletes it and refuses further submissions from the same network for 30 days. The section updates live when a submission arrives. | |
| 50 | + | ||
| 51 | + | An approved issue is rendered as untrusted Markdown: raw HTML is dropped, images are never loaded (their alt text is shown), only `http`, `https` and `mailto` links are kept, each with `rel="nofollow noopener noreferrer ugc"`, and every other link loses its link and keeps its text. | |
| 52 | + | ||
| 53 | + | No address is stored. The limits and the ban key on an HMAC of the network address made with a server key, and the submission keeps only that hash. | |
| 54 | + | ||
| 55 | + | The limits see the address of the client only if `ERMITE_TRUSTED_PROXIES` lists your reverse proxy; otherwise every visitor shares the proxy's address and one budget (see [configuration](configuration.md)). | |
| @@ -20,7 +20,7 @@ All commands take `--json`. `--body -` and `--body-file -` read standard input. | |||||
| 20 | 20 | ||||
| 21 | - `off` (default): issues are disabled. | 21 | - `off` (default): issues are disabled. | ||
| 22 | - `owner`: the owner and tokens with `issue:write` write issues. | 22 | - `owner`: the owner and tokens with `issue:write` write issues. | ||
| 23 | - | - `public`: the anonymous moderated form; not available yet, the server refuses it. | 23 | + | - `public`: anyone may propose an issue through a moderated form (see [Public form and moderation](#public-form-and-moderation)). The repository must be public too. |
| 24 | 24 | ||||
| 25 | ## Who can write | 25 | ## Who can write | ||
| 26 | 26 | ||||
| @@ -39,3 +39,17 @@ Merge requests and issues of a repository draw `#n` from one sequence, so a numb | |||||
| 39 | The signed-in owner has an Inbox at `/-/inbox`, reached from the **Inbox** button at the top left of the home page, which shows the number of open items. It lists the open merge requests and the open issues of every repository, most recently updated first. The counters at the top (`N merge requests · M issues`) always count everything; `?repo=<name>` restricts the two lists to one repository, and the repository links under the counters set it. Repositories with issues off contribute no issues. | 39 | The signed-in owner has an Inbox at `/-/inbox`, reached from the **Inbox** button at the top left of the home page, which shows the number of open items. It lists the open merge requests and the open issues of every repository, most recently updated first. The counters at the top (`N merge requests · M issues`) always count everything; `?repo=<name>` restricts the two lists to one repository, and the repository links under the counters set it. Repositories with issues off contribute no issues. | ||
| 40 | 40 | ||||
| 41 | The page updates live: merge request and issue events of any repository refresh the counters and the lists. Anyone who is not the signed-in owner, including a token, gets the same 404 as for an unknown page, and the same answer for the `owner` event stream it follows. | 41 | The page updates live: merge request and issue events of any repository refresh the counters and the lists. Anyone who is not the signed-in owner, including a token, gets the same 404 as for an unknown page, and the same answer for the `owner` event stream it follows. | ||
| 42 | + | ||||
| 43 | + | ## Public form and moderation | |||
| 44 | + | ||||
| 45 | + | With `issues` set to `public` on a public repository, a visitor who is not signed in finds a **New issue** button on the Issues tab, which opens `/<repo>/issues/new`. The form needs JavaScript: the page solves a short proof of work in a worker while the visitor writes (a second or so; harder after many recent submissions), and the button stays disabled until it is done and a few seconds have passed. Without JavaScript the form stays hidden and the page says why. A repository that is private, or whose mode is `off` or `owner`, has no such page: it answers the same 404 as an unknown one. | |||
| 46 | + | ||||
| 47 | + | Limits: a title of at most 120 characters, a description of at most 10,000, an optional name of at most 40 (not verified). Each network may submit 3 issues per hour and 10 per day. At most 200 submissions await moderation; beyond that the form says submissions are paused. A submission never appears on its own: it is stored as pending and shows no id to the visitor. | |||
| 48 | + | ||||
| 49 | + | The owner moderates in the Inbox, in the first section, **Awaiting moderation**, whose count is in the counters row. Each submission shows its repository, age, name (or "anonymous"), title and the start of the description, as plain text, with three buttons: **Approve** opens it as the next issue of the repository (numbers are shared with merge requests), **Reject** deletes it, **Reject and ban** deletes it and refuses further submissions from the same network for 30 days. The section updates live when a submission arrives. | |||
| 50 | + | ||||
| 51 | + | An approved issue is rendered as untrusted Markdown: raw HTML is dropped, images are never loaded (their alt text is shown), only `http`, `https` and `mailto` links are kept, each with `rel="nofollow noopener noreferrer ugc"`, and every other link loses its link and keeps its text. | |||
| 52 | + | ||||
| 53 | + | No address is stored. The limits and the ban key on an HMAC of the network address made with a server key, and the submission keeps only that hash. | |||
| 54 | + | ||||
| 55 | + | The limits see the address of the client only if `ERMITE_TRUSTED_PROXIES` lists your reverse proxy; otherwise every visitor shares the proxy's address and one budget (see [configuration](configuration.md)). | |||
M skills/ermite/CLI.md +1 -1
| @@ -65,7 +65,7 @@ Merge request JSON: `repo`, `number`, `title`, `description`, `source_branch`, ` | |||
| 65 | 65 | ||
| 66 | 66 | ## Issues | |
| 67 | 67 | ||
| 68 | - | Issues share the numbering of merge requests and must be enabled per repository: `repo edit <repo> --issues off|owner|public` (`repo:admin`; default `off`; `public` is not available yet). Reading and writing needs a server with the `issues` feature. | |
| 68 | + | Issues share the numbering of merge requests and must be enabled per repository: `repo edit <repo> --issues off|owner|public` (`repo:admin`; default `off`; `public` also opens a moderated form to visitors of a public repository). Reading and writing needs a server with the `issues` feature. | |
| 69 | 69 | ||
| 70 | 70 | | Command | Scope | Notes | | |
| 71 | 71 | |---|---|---| | |
| @@ -65,7 +65,7 @@ Merge request JSON: `repo`, `number`, `title`, `description`, `source_branch`, ` | |||||
| 65 | 65 | ||||
| 66 | ## Issues | 66 | ## Issues | ||
| 67 | 67 | ||||
| 68 | - | Issues share the numbering of merge requests and must be enabled per repository: `repo edit <repo> --issues off|owner|public` (`repo:admin`; default `off`; `public` is not available yet). Reading and writing needs a server with the `issues` feature. | 68 | + | Issues share the numbering of merge requests and must be enabled per repository: `repo edit <repo> --issues off|owner|public` (`repo:admin`; default `off`; `public` also opens a moderated form to visitors of a public repository). Reading and writing needs a server with the `issues` feature. |
| 69 | 69 | ||||
| 70 | | Command | Scope | Notes | | 70 | | Command | Scope | Notes | | ||
| 71 | |---|---|---| | 71 | |---|---|---| | ||