From fdf4164e49fe21373371ae570e6bd580985ccb0b Mon Sep 17 00:00:00 2001 From: aditeyabaral Date: Sun, 13 Sep 2026 14:12:42 -0500 Subject: [PATCH 1/3] docs: say how to set the metrics token on a local run The section only showed `docker run -e`, which left the local mechanism to be guessed. A token in `.env` is the natural guess and it does not work: `.env` is read by the test suite, never by the application, so it looks configured while the endpoint stays open. Both are now stated. Dropped the `openssl rand -hex 32` line with it. How to generate a token is the reader's choice, not something this project needs an opinion on. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01VU7YUhP71KSsotWQ1H7CRH --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 331e6b4..bf9cab9 100644 --- a/README.md +++ b/README.md @@ -553,10 +553,16 @@ expect. Set the `METRICS_TOKEN` environment variable on the server to require a instead: ```bash -TOKEN=$(openssl rand -hex 32) # keep it: whatever scrapes the endpoint needs the same value -docker run --name pesu-auth -d -p 5000:5000 -e METRICS_TOKEN="$TOKEN" pesu-auth +# Deployed: an environment variable on the service +docker run --name pesu-auth -d -p 5000:5000 -e METRICS_TOKEN= pesu-auth + +# Running from source: pass it to the process +METRICS_TOKEN= uv run python -m app.app ``` +`.env` is read by the test suite, never by the application, so a token there does not protect a +running server. + With it set, a request must carry that token or the endpoint answers `401` with `WWW-Authenticate: Bearer` and the same error body as every other failure. Both formats are covered, so `?fmt=json` is not a way around it. From cefab725187f71af45a8d48ad7bf791a548438df Mon Sep 17 00:00:00 2001 From: aditeyabaral Date: Sun, 13 Sep 2026 14:12:42 -0500 Subject: [PATCH 2/3] chore: bump version to 4.4.0 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01VU7YUhP71KSsotWQ1H7CRH --- pyproject.toml | 2 +- uv.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b07d09b..01a8f69 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "pesu-auth" -version = "4.3.0" +version = "4.4.0" description = "A simple API to authenticate PESU credentials using PESU Academy." readme = "README.md" requires-python = ">=3.14" diff --git a/uv.lock b/uv.lock index 7f9bc05..8c62995 100644 --- a/uv.lock +++ b/uv.lock @@ -630,7 +630,7 @@ wheels = [ [[package]] name = "pesu-auth" -version = "4.3.0" +version = "4.4.0" source = { editable = "." } dependencies = [ { name = "fastapi" }, From 100a5109645ecf88b85fcd26e15efd58d72da345 Mon Sep 17 00:00:00 2001 From: aditeyabaral Date: Sun, 13 Sep 2026 14:19:05 -0500 Subject: [PATCH 3/3] docs: complete the /metrics token and response documentation Three gaps, found by checking the section against what the endpoint actually does rather than by rereading it. **The three states of the token are now a table.** Unset and set were described in prose; what happens to a credential sent to an *unconditionally open* endpoint was not written down anywhere. It is ignored rather than rejected, which matters to anyone pointing a scraper at more than one environment. The blank case moves into the same table from a trailing sentence, so all three sit together. **`/metrics` had no response-code table** where every other endpoint documents one, and `500` was absent from the README entirely despite being in the published schema. The table now lists 200, 400, 401 and 500 with the condition for each. **The Authorize button went unmentioned**, which is how most people will first try the token, and it needs the value pasted with no `Bearer ` prefix. Also trimmed the sentence that repeated what the new table says. Every claim in the section was checked against a running server, in both the configured and unconfigured states, including that `fmt` validation and the token are independent: a valid token with a bad `fmt` is a 400, no credential is a 401. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01VU7YUhP71KSsotWQ1H7CRH --- README.md | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index bf9cab9..690016a 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,15 @@ curl http://localhost:5000/metrics # Prometheus text, for a scr curl http://localhost:5000/metrics?fmt=json | jq # the same numbers, for a human ``` +#### Responses + +| **Code** | **When** | +| -------- | ------------------------------------------------------------------------------------------ | +| `200` | The counters, in the format named by `fmt` | +| `400` | `fmt` was something other than `prometheus` or `json` | +| `401` | A token is configured and the request did not carry it. Carries `WWW-Authenticate: Bearer` | +| `500` | An unexpected failure, rendered by the catch-all handler like on any other endpoint | + #### How collection works Everything is counted **in this process, in memory**. There is no database and no external dependency, and the counters @@ -548,9 +557,14 @@ which is `null` rather than absent when nothing has been recorded yet, so the sh #### Protecting the endpoint -`/metrics` is **open by default**, which is what a local run and the Docker instructions above -expect. Set the `METRICS_TOKEN` environment variable on the server to require a bearer token -instead: +`/metrics` is **open unless a token is configured**, through the `METRICS_TOKEN` environment +variable. + +| `METRICS_TOKEN` | Behaviour of `/metrics` | +| --------------- | ---------------------------------------------------------------------- | +| unset | Open. A credential sent anyway is **ignored, not rejected** | +| blank | Same as unset — an empty value means "no token", not "the empty token" | +| set | Every request must carry that token, in both formats | ```bash # Deployed: an environment variable on the service @@ -563,18 +577,19 @@ METRICS_TOKEN= uv run python -m app.app `.env` is read by the test suite, never by the application, so a token there does not protect a running server. -With it set, a request must carry that token or the endpoint answers `401` with -`WWW-Authenticate: Bearer` and the same error body as every other failure. Both formats are -covered, so `?fmt=json` is not a way around it. +A rejection carries `WWW-Authenticate: Bearer` and the same error body as every other failure. ```bash curl http://localhost:5000/metrics # 401 curl -H "Authorization: Bearer " http://localhost:5000/metrics # 200 ``` -The variable is read once at startup, so changing it needs a restart. Leaving it blank counts as -unset. No other endpoint is affected — `/health` in particular stays open, since uptime monitors -and the hosting platform's own health check send no credentials. +The interactive docs at `/` carry an **Authorize** button for it. Paste the token there with no +`Bearer ` prefix; Swagger adds that itself. + +The variable is read once at startup, so changing it needs a restart. No other endpoint is +affected — `/health` in particular stays open, since uptime monitors and the hosting platform's own +health check send no credentials. #### Scraping the endpoint