detached e687d9c

docs: public issue form and moderation

commit
e687d9cb37df6ea22c6f33f43d2bf9344322661f
author
brice · · 2026-10-19 07:42 UTC
parent
cce8cfa
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · 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
8484 ermite completion bash|zsh|fish
8585 ```
8686
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).
8888
8989 ## Output
9090
@@ -84,7 +84,7 @@ ermite version # client and server versions
84 ermite completion bash|zsh|fish84 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 ## Output89 ## Output
90 90
M docs/issues.md +15 -1
@@ -20,7 +20,7 @@ All commands take `--json`. `--body -` and `--body-file -` read standard input.
2020
2121 - `off` (default): issues are disabled.
2222 - `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.
2424
2525 ## Who can write
2626
@@ -39,3 +39,17 @@ Merge requests and issues of a repository draw `#n` from one sequence, so a numb
3939 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.
4040
4141 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 write25 ## 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`, `
6565
6666 ## Issues
6767
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.
6969
7070 | Command | Scope | Notes |
7171 |---|---|---|
@@ -65,7 +65,7 @@ Merge request JSON: `repo`, `number`, `title`, `description`, `source_branch`, `
65 65
66 ## Issues66 ## 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 |---|---|---|

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 41

↑↓ moveenter openesc close