release: 0.93.1 (bug/preview-crashes-the-tracker)
This commit is contained in:
@@ -7,6 +7,14 @@ edit the release notes and re-run the generator.
|
|||||||
|
|
||||||
Upgrading, pinning a version and rolling back: [docs/self-hosting.md](docs/self-hosting.md#upgrading).
|
Upgrading, pinning a version and rolling back: [docs/self-hosting.md](docs/self-hosting.md#upgrading).
|
||||||
|
|
||||||
|
## 0.93.1 — 2026-09-20
|
||||||
|
|
||||||
|
The report composer's preview works again.
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
- Looking at a report before sending it said "the issue tracker isn't answering" — every time, for everyone. The preview asked the tracker to resolve links against the repository, and a report always carries something that looks like a commit hash: an id of the tab, of a request. On a tracker older than Gitea 1.27.2 that request does not fail, it stops the tracker — so the preview now asks for the rendering without the repository, which shows the same tables, lists and code, and can no longer take a tracker down. Sending a report was never affected.
|
||||||
|
|
||||||
## 0.93.0 — 2026-09-20
|
## 0.93.0 — 2026-09-20
|
||||||
|
|
||||||
A way to report a fault from inside the app: record what you did, mark the steps, attach screenshots — and the app writes the report for you, with the logs of exactly that session attached.
|
A way to report a fault from inside the app: record what you did, mark the steps, attach screenshots — and the app writes the report for you, with the logs of exactly that session attached.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ before a line of this was written (plans/e16-debug-issue.md, S0).
|
|||||||
|
|
||||||
Configured by an admin (sysconfig `issues_gitea_url` / `_repo` / `_token`, the token encrypted at
|
Configured by an admin (sysconfig `issues_gitea_url` / `_repo` / `_token`, the token encrypted at
|
||||||
rest). The repository must be PRIVATE: an issue carries its reporter's log — page titles, filter
|
rest). The repository must be PRIVATE: an issue carries its reporter's log — page titles, filter
|
||||||
values, at Teljes what they typed into search — and a public repository would publish it. That is
|
values, at Teljes (TRACE) what they typed into search — and a public repository would publish it. That is
|
||||||
checked on every send, not only in the admin's "test connection", because a repository can be made
|
checked on every send, not only in the admin's "test connection", because a repository can be made
|
||||||
public after the fact.
|
public after the fact.
|
||||||
|
|
||||||
@@ -154,9 +154,22 @@ def check(db: Session) -> dict:
|
|||||||
|
|
||||||
|
|
||||||
def preview(db: Session, text: str) -> str:
|
def preview(db: Session, text: str) -> str:
|
||||||
"""The body as Gitea itself will render it (its markdown flavour, its sanitiser)."""
|
"""The body as Gitea itself will render it (its markdown flavour, its sanitiser).
|
||||||
with _client(_settings(db)) as (client, repo):
|
|
||||||
r = _call(client, "POST", "/markdown", json={"Text": text, "Mode": "gfm", "Context": repo})
|
**No `Context`, deliberately — a repository context here does not fail the call, it kills the
|
||||||
|
tracker.** With one, Gitea's post-processor turns every hex-shaped word into a commit link, and
|
||||||
|
on the API's render path the commit checker it asks is nil: the whole Gitea process segfaults
|
||||||
|
and restarts, taking the git server (and, here, the container registry) down with it. Every
|
||||||
|
report carries hex — a tab id, a request id — so this was not an edge case but the only case.
|
||||||
|
Measured on throwaway instances (2026-09-20): `{"Mode": "gfm", "Context": "<repo>"}` with
|
||||||
|
`5645b1c0ae01` in the text crashes 1.26.4 and 1.27.1 and is fixed in 1.27.3 — but a self-hoster
|
||||||
|
runs whatever version they run, so the payload stays safe here rather than relying on theirs.
|
||||||
|
Dropping `Context` is not a downgrade of the preview: measured against the same body, the HTML
|
||||||
|
keeps its tables, its task lists and its highlighted code blocks. It only stops resolving
|
||||||
|
repo-relative links (a hash, a `#123`), which the issue page itself still resolves.
|
||||||
|
"""
|
||||||
|
with _client(_settings(db)) as (client, _repo):
|
||||||
|
r = _call(client, "POST", "/markdown", json={"Text": text, "Mode": "gfm"})
|
||||||
return r.text
|
return r.text
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -786,6 +786,7 @@ class FakeGitea:
|
|||||||
self.redirect = False # an http:// address behind a proxy that sends it to https
|
self.redirect = False # an http:// address behind a proxy that sends it to https
|
||||||
self.garbage_asset = False # a 2xx that is not the API's answer (a proxy's page)
|
self.garbage_asset = False # a 2xx that is not the API's answer (a proxy's page)
|
||||||
self.patched_body: str | None = None
|
self.patched_body: str | None = None
|
||||||
|
self.markdown_payloads: list[dict] = [] # what the preview asked the tracker to render
|
||||||
|
|
||||||
def handler(self, request: httpx.Request) -> httpx.Response:
|
def handler(self, request: httpx.Request) -> httpx.Response:
|
||||||
path = request.url.path.removeprefix("/api/v1")
|
path = request.url.path.removeprefix("/api/v1")
|
||||||
@@ -826,6 +827,7 @@ class FakeGitea:
|
|||||||
self.patched_body = json.loads(request.content)["body"]
|
self.patched_body = json.loads(request.content)["body"]
|
||||||
return httpx.Response(201, json={"number": 7})
|
return httpx.Response(201, json={"number": 7})
|
||||||
if request.method == "POST" and path == "/markdown":
|
if request.method == "POST" and path == "/markdown":
|
||||||
|
self.markdown_payloads.append(json.loads(request.content))
|
||||||
return httpx.Response(200, text="<h3>Steps</h3>")
|
return httpx.Response(200, text="<h3>Steps</h3>")
|
||||||
return httpx.Response(404, json={"message": "not found"})
|
return httpx.Response(404, json={"message": "not found"})
|
||||||
|
|
||||||
@@ -1180,6 +1182,20 @@ def test_the_preview_is_the_trackers_own_rendering(gitea_fake, db, make_user, as
|
|||||||
assert stranger.post(f"/api/debug-sessions/{sid}/issue").status_code == 404
|
assert stranger.post(f"/api/debug-sessions/{sid}/issue").status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
def test_the_preview_never_asks_the_tracker_for_a_repository_context(
|
||||||
|
gitea_fake, db, make_user, as_user
|
||||||
|
):
|
||||||
|
"""A `Context` makes Gitea hunt for commit links, and on the API's render path that hunt
|
||||||
|
dereferences a nil checker: the tracker's whole process segfaults. Every report carries a
|
||||||
|
hex-shaped id, so the payload — not the text — is what has to stay safe (measured against
|
||||||
|
1.26.4 / 1.27.1, fixed upstream in 1.27.3; a self-hoster's version is not ours to pick)."""
|
||||||
|
owner = as_user(make_user())
|
||||||
|
sid = _start(owner)["id"]
|
||||||
|
text = "| tab | 5645b1c0ae01 |"
|
||||||
|
assert owner.post(f"/api/debug-sessions/{sid}/preview", json={"text": text}).status_code == 200
|
||||||
|
assert gitea_fake.markdown_payloads == [{"Text": text, "Mode": "gfm"}]
|
||||||
|
|
||||||
|
|
||||||
def test_the_admin_connection_test_names_what_is_wrong(gitea_fake, db, make_user, as_user):
|
def test_the_admin_connection_test_names_what_is_wrong(gitea_fake, db, make_user, as_user):
|
||||||
admin = as_user(make_user(role="admin"))
|
admin = as_user(make_user(role="admin"))
|
||||||
r = admin.post("/api/admin/config/test-issues")
|
r = admin.post("/api/admin/config/test-issues")
|
||||||
|
|||||||
@@ -14,6 +14,14 @@ export interface ReleaseEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const RELEASE_NOTES: ReleaseEntry[] = [
|
export const RELEASE_NOTES: ReleaseEntry[] = [
|
||||||
|
{
|
||||||
|
version: "0.93.1",
|
||||||
|
date: "2026-09-20",
|
||||||
|
summary: "The report composer's preview works again.",
|
||||||
|
fixes: [
|
||||||
|
'Looking at a report before sending it said "the issue tracker isn\'t answering" — every time, for everyone. The preview asked the tracker to resolve links against the repository, and a report always carries something that looks like a commit hash: an id of the tab, of a request. On a tracker older than Gitea 1.27.2 that request does not fail, it stops the tracker — so the preview now asks for the rendering without the repository, which shows the same tables, lists and code, and can no longer take a tracker down. Sending a report was never affected.',
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
version: "0.93.0",
|
version: "0.93.0",
|
||||||
date: "2026-09-20",
|
date: "2026-09-20",
|
||||||
|
|||||||
Reference in New Issue
Block a user