Entering a wrong token looked exactly like entering none: the page came back unchanged, so a typo, a token from the wrong repository and a rotated one were indistinguishable from a broken button. The page asks the server before it stores anything. A new endpoint answers 204 or 403 for a token in the header — the header, because this is asked before a cookie exists and because a foreign page cannot set one — and the key reports a refusal at once, naming where the right token lives, without storing it. A stored token the server no longer accepts turns the key red instead of leaving the page looking untouched. The instance also logs the absolute path of its token file at startup: it is relative to the service's working directory, which on an instance serving several repositories is the one the systemd unit names and not any of the others, and a token from the wrong one is silently just a wrong token. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: mhoennig <michael@hoennig.de> Reviewed-on: #47
76 lines
4.1 KiB
Markdown
76 lines
4.1 KiB
Markdown
> **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, not as current documentation.
|
|
|
|
## Related Links
|
|
|
|
- [PR#43](2026-09-09-PR%2343-private-repositories-and-quota-severity.md) — introduced the key in the header and the token cookie.
|
|
|
|
## The Problem
|
|
|
|
Entering the control token has no visible effect when the token is wrong, and no way to tell that apart from a bug.
|
|
|
|
The page comes back exactly as it was: the actions stay grey, a private repository stays hidden, the key stays pale.
|
|
That is the same picture as before entering anything, so a typo, a token copied from the wrong repository, or one that has been rotated all look identical — and identical to "the button is broken".
|
|
|
|
The wrong-repository case is easy to walk into. The token file is `.git/werkator/control-token` *relative to the working directory of the service*, which on an instance serving several repositories is the one its systemd unit names and not any of the others. Nothing said which one that is, and running `werkator control-token` in the wrong repository does not warn — it creates and prints a different token.
|
|
|
|
## Non-Goals
|
|
|
|
- No change to what the token protects, or to how it travels. It stays a header for anything that acts and a cookie for what may be seen.
|
|
- No way to read the token out of the server. The new endpoint confirms a token that is already known; it never hands one out.
|
|
|
|
## The Scenarios
|
|
|
|
### Feature: telling a wrong token from no token
|
|
|
|
#### Scenario#47.01: The server answers whether a token is the right one
|
|
|
|
So that the page can say what is wrong before it stores anything.
|
|
|
|
- **Given** the correct control token in the request header
|
|
- **When** `GET /api/control-token/verify` is called
|
|
- **Then** it answers `204` with an empty body
|
|
- **Given** a wrong token, or none
|
|
- **Then** it answers `403`, alike, and says nothing further
|
|
- **And** the answer is never stored by a cache
|
|
|
|
##### Verified by
|
|
|
|
- [ControlTokenApiControllerTest](../../src/test/kotlin/de/hoennig/werkator/server/ControlTokenApiControllerTest.kt)
|
|
|
|
#### Scenario#47.02: The key says what happened
|
|
|
|
- **Given** a token entered at the key in the header
|
|
- **When** the server refuses it
|
|
- **Then** it is not stored, and a message says so and where the right one lives
|
|
- **When** the server accepts it
|
|
- **Then** it is stored and the page fetched afresh, in its operator form
|
|
- **Given** a stored token that leaves the page in its visitor form
|
|
- **Then** the key is red
|
|
- **and** its tooltip says the token is not accepted when the server refuses it
|
|
- **and** says the token is correct but is not arriving when the server accepts it — the cookie is being blocked or dropped on the way, which used to look exactly like a wrong token
|
|
|
|
### Feature: finding the token
|
|
|
|
#### Scenario#47.03: The instance says where its token is
|
|
|
|
- **When** the server starts
|
|
- **Then** it logs the absolute path of its control-token file once
|
|
|
|
## The Solution
|
|
|
|
`ControlTokenApiController` answers one question — is this the token — from the header only, with `204` or `403` and no body.
|
|
The header, not the cookie, because the page asks before setting a cookie, and because a header cannot be sent by a foreign page.
|
|
|
|
The key button asks before storing anything. A refused token is reported at once, naming where the right one is, and is not stored, so nothing has to be undone. An accepted one is stored and the page fetched afresh, as before.
|
|
|
|
A token that was accepted once and is not any more used to be invisible; on load the key now compares "something is stored" with "the server trusts me" and turns red when the two disagree.
|
|
It then asks the same endpoint with the header to tell the two causes apart, because a wrong token and a cookie that never arrives produce the identical page and need opposite reactions.
|
|
|
|
`ServerConfiguration` logs the resolved absolute path of the token file at startup, because "relative to the working directory" is not something an operator can see from the outside.
|
|
|
|
## Additional Changes
|
|
|
|
- Version 1.5.3 and its release-notes entry, since this is what gets deployed.
|