Skip to content

docs: complete the /metrics token and response documentation - #159

Merged
aditeyabaral merged 3 commits into
pesu-dev:devfrom
aditeyabaral:docs/caller-facing-metrics-auth
Sep 13, 2026
Merged

aditeyabaral merged 3 commits into
pesu-dev:devfrom
aditeyabaral:docs/caller-facing-metrics-auth

Conversation

@aditeyabaral

@aditeyabaral aditeyabaral commented Sep 13, 2026

Copy link
Copy Markdown
Member

📌 Description

Documentation only. The /metrics section was audited against what the endpoint actually does —
by extracting every metric family and JSON field from the code and checking each appears, and by
exercising the endpoint in every configuration — rather than by rereading it. All 24 metric
families and all 20 JSON fields were already covered. Four things were not.

1. Only docker run -e was shown, so the mechanism for a local run was left to be guessed —
and the natural guess is a line in .env, which silently does not work. .env is read by the test
suite, never by the application, so the endpoint stays open while looking configured. Both the
working local form and that caveat are now written down.

# Deployed: an environment variable on the service
docker run --name pesu-auth -d -p 5000:5000 -e METRICS_TOKEN=<token> pesu-auth

# Running from source: pass it to the process
METRICS_TOKEN=<token> uv run python -m app.app

The openssl rand -hex 32 suggestion is dropped with it. How to generate a token is the reader's
choice, not something this project needs an opinion on.

2. The three states of the token are now a table. Unset and set were described in prose, but
what happens to a credential sent to an endpoint that requires none was written down nowhere — it
is ignored rather than rejected, which matters to anyone pointing one scraper at several
environments. The blank case joins them from a trailing sentence, so all three sit together.

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

3. /metrics had no response-code table, where every other endpoint documents one, and 500
was missing from the README entirely despite being in the published schema. It now lists 200,
400, 401 and 500 with the condition for each.

4. The Authorize button went unmentioned — the way most people will first try the token, and it
needs the value pasted with no Bearer prefix, since Swagger adds that itself.

No behaviour change. The contract is unchanged from #158: a configured token is enforced, an
unset or blank one means no check.

ℹ️ Fixes / Related Issues
Related: #158 — added the token and the section this clarifies.

🧱 Type of Change

  • 🐛 Bug fix – Non-breaking fix for a functional/logic error
  • ✨ New feature – Adds functionality without breaking existing APIs
  • ⚠️ Breaking change – Introduces backward-incompatible changes (API, schema, etc.)
  • 📝 Documentation update – README, docstrings, OpenAPI tags, etc.
  • 🧪 Test suite change – Adds/updates unit, functional, or integration tests
  • ⚙️ CI/CD pipeline update – Modifies GitHub Actions, pre-commit, or Docker build
  • 🧹 Code quality / Refactor – Improves structure, readability, or style (no functional changes)
  • 🐢 Performance improvement – Speeds up auth, scraping, or reduces I/O
  • 🕵️ Debug/logging enhancement – Adds or improves logging/debug support
  • 🔧 Developer tooling – Scripts, benchmarks, local testing improvements
  • 🔒 Security fix – Addresses auth/session/data validation vulnerabilities
  • 🧰 Dependency update – Updates libraries in requirements.txt, pyproject.toml

🧪 How Has This Been Tested?

  • Unit Tests (tests/unit/)
  • Functional Tests (tests/functional/)
  • Integration Tests (tests/integration/)
  • Manual Testing

276 tests, 100.00% coverage, unchanged — no code is touched. Completeness was checked
programmatically against FAMILIES and MetricsModel.model_fields, not by eye. pre-commit run --all-files
passes 12/12 hooks.

The claims the README now makes were each checked against a running server, since documenting them
is the whole point of the change:

Configuration /metrics
nothing set 200, and a credential sent anyway is ignored rather than rejected
METRICS_TOKEN= (blank) 200 — blank counts as unset
METRICS_TOKEN=<token> uv run python -m app.app 401 bare, 401 wrong, 200 correct, both fmt values
docker run without -e 200
docker run -e METRICS_TOKEN=… 401 bare, 200 correct
a token in .env only 200 — the app never reads the file, which is the caveat documented here
set, valid token, ?fmt=xml 400fmt validation and the token are independent
unset, ?fmt=xml 400
Render staging (v4.3.0) 401 bare, 200 correct — verified live

⚙️ Test Configuration:

  • OS: Linux
  • Python: 3.14.4 via uv
  • Docker build tested

✅ Checklist

  • My code follows the CONTRIBUTING.md guidelines
  • I've performed a self-review of my changes
  • I've added/updated necessary comments and docstrings
  • I've updated relevant docs (README or endpoint docs)
  • No new warnings introduced
  • I've added tests to cover my changes
  • All tests pass locally (scripts/run_tests.py)
  • I've run linting and formatting (pre-commit run --all-files)
  • Docker image builds and runs correctly
  • Changes are backwards compatible (if applicable)
  • Feature flags or .env vars updated (if applicable)
  • I've tested across multiple environments (if applicable)
  • Benchmarks still meet expected performance (scripts/benchmark/benchmark_requests.py)

Unchecked items carry no work: no code, so no docstrings and no new tests; no new variables; and
nothing on a request path a benchmark measures.

🛠️ Affected API Behaviour

  • app/app.py – Modified /authenticate route logic
  • app/pesu.py – Updated scraping or authentication handling

Only README.md.

🧩 Models

  • app/models/request.py – Input validation or request schema changes
  • app/models/response.py – Authentication response formatting
  • app/models/profile.py – Profile extraction logic

🐳 DevOps & Config

  • Dockerfile – Changes to base image or build process
  • .github/workflows/*.yaml – CI/CD pipeline or deployment updates
  • pyproject.toml / requirements.txt – Dependency version changes
  • .pre-commit-config.yaml – Linting or formatting hook changes

Project version only, 4.3.0 → 4.4.0, plus the matching uv.lock. No dependency changes.

📊 Benchmarks & Analysis

  • scripts/benchmark/benchmark_requests.py – Performance or latency measurement changes
  • scripts/benchmark/analyze_benchmark.py – Benchmark result analysis changes
  • scripts/run_tests.py – Custom test runner logic or behavior updates

🧠 Additional Notes

Two things were tried in this branch and deliberately dropped.

Rewriting the Swagger strings. The Authorize dialog and the documented 401 name
METRICS_TOKEN and describe a server-side environment variable, which a caller reading Swagger
cannot act on. They were rewritten to describe the contract instead, then reverted at the
maintainer's preference
— the explicit, mechanism-naming version is the wanted one. Not worth
revisiting.

load_dotenv() in the application. Making .env configure a running server would mean moving
python-dotenv out of the dev group into the runtime dependencies, since the image is built with
uv sync --no-dev, and it would make a local run demand a token the moment a developer put one
in .env — the opposite of what local development wants. Documenting
METRICS_TOKEN=<token> <command> covers the case with no dependency and no surprise.

One finding worth keeping from that attempt, should anyone revisit it: load_dotenv() resolves
against the working directory under python -m, not the package. A server started from
anywhere but the repository root would have loaded nothing and served metrics openly while
appearing configured.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VU7YUhP71KSsotWQ1H7CRH

@aditeyabaral
aditeyabaral requested a review from a team as a code owner September 13, 2026 17:32
@aditeyabaral aditeyabaral changed the title docs: write the metrics token docs for callers, not operators docs: fix the metrics token documentation's audience and its missing local instructions Sep 13, 2026
aditeyabaral and others added 2 commits September 13, 2026 14:12
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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VU7YUhP71KSsotWQ1H7CRH
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VU7YUhP71KSsotWQ1H7CRH
@aditeyabaral
aditeyabaral force-pushed the docs/caller-facing-metrics-auth branch from 993ac07 to cefab72 Compare September 13, 2026 19:13
@aditeyabaral aditeyabaral changed the title docs: fix the metrics token documentation's audience and its missing local instructions docs: say how to set the metrics token on a local run Sep 13, 2026
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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VU7YUhP71KSsotWQ1H7CRH
@aditeyabaral aditeyabaral changed the title docs: say how to set the metrics token on a local run docs: complete the /metrics token and response documentation Sep 13, 2026
@aditeyabaral
aditeyabaral merged commit 4b306ec into pesu-dev:dev Sep 13, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant