Repository navigation
Configuration
Everything is configured through environment variables. There is no config file. Most are read once at import, so changing one means restarting the container.
| Variable | Default | What it does |
|---|---|---|
DATABASE_URL |
postgresql://reportmate:password@localhost:5432/reportmate |
PostgreSQL connection URL. Both postgresql:// and postgres:// schemes are accepted; a query string is ignored. The default is a placeholder, not a usable production value. |
At least one credential must also be set, or nothing but the health probes is reachable — see the authentication table below.
| Variable | Default | What it does |
|---|---|---|
DB_SSL |
true |
TLS to PostgreSQL. Set to false, 0, no, or disable for a local or in-cluster server with no TLS. |
DB_POOL_MIN |
2 |
Connections the pool keeps cached. |
DB_POOL_MAX |
40 |
Pool ceiling and maximum connections. Matched to Starlette's threadpool so every worker can hold one; lowering it below the threadpool size makes bursts queue. |
Each pooled connection gets statement_timeout = 120s and a 130-second socket
timeout. Neither is configurable by environment variable.
| Variable | Default | What it does |
|---|---|---|
REPORTMATE_PASSPHRASE |
unset | Shared fleet passphrase accepted in X-Client-Passphrase or X-API-PASSPHRASE. Comma-separated: the first entry is current, later entries are deprecated-but-accepted so you can rotate without an outage. |
API_INTERNAL_SECRET |
unset | Value for X-Internal-Secret, the dashboard-BFF-to-API hop. Also required for PUT /api/v1/settings. |
DISABLE_AUTH |
false |
Bypasses all authentication. Development only — the app refuses to boot with it set in a production-like configuration. |
TRUST_EASYAUTH_PRINCIPAL_HEADER |
false |
Honour X-MS-CLIENT-PRINCIPAL-ID as proof of identity. Only safe when a platform that strips inbound X-MS-* headers (Azure Easy Auth) fronts the app. |
APP_ENV |
unset (falls back to ENVIRONMENT) |
Deployment marker. development, dev, local, test, testing allow DISABLE_AUTH; production, prod, staging, stage refuse it. |
The startup guard treats a deployment as production-like when APP_ENV names
a prod or staging environment or when either auth secret is configured, so
you do not have to add a new marker for it to work.
Inert until ENABLE_OIDC_AUTH is true and both issuers and audience are set.
| Variable | Default | What it does |
|---|---|---|
ENABLE_OIDC_AUTH |
false |
Master switch. |
OIDC_ISSUERS |
empty | Comma-separated trusted issuer URLs. A token whose iss is not listed is refused before any crypto runs. |
OIDC_AUDIENCE |
empty | Comma-separated accepted audiences. |
OIDC_JWKS_URI |
unset | Pin a JWKS endpoint instead of using each issuer's /.well-known/openid-configuration. |
OIDC_ALGORITHMS |
RS256,RS384,RS512,ES256,ES384 |
Accepted signature algorithms. none and HS* are excluded on purpose. |
OIDC_ROLE_SCOPE_MAP |
empty | JSON object merged over the built-in map, e.g. to grant scopes by group id. |
OIDC_DEFAULT_SCOPES |
empty | Comma-separated fallback when a valid token maps to nothing. Without it such a token is rejected. |
OIDC_LEEWAY |
60 |
Clock skew allowance in seconds. |
The built-in role map recognises ReportMate.Read, ReportMate.Ingest,
ReportMate.Admin, the bare names read / ingest / admin, and reader.
admin grants all three scopes so an admin token can still perform a plain
GET. Roles, groups, and scp / scope claims are all read and unioned.
| Variable | Default | What it does |
|---|---|---|
RATE_LIMIT_PER_MINUTE |
120 |
Per-device bucket, keyed on the X-Device-Serial header. Clients that do not send it are governed by the address bucket alone. |
RATE_LIMIT_IP_PER_MINUTE |
3000 |
Per-address flood shield, keyed on the first hop of X-Forwarded-For when present. |
Both buckets are counted on every request. A caller presenting the valid internal secret bypasses them entirely.
| Variable | Default | What it does |
|---|---|---|
MAX_DECOMPRESSED_BODY_BYTES |
67108864 (64 MiB) |
Ceiling on what a compressed request body may inflate to. Enforced during the inflate, not after. |
INGEST_FAILURES_RETENTION_DAYS |
30 |
Age-out window for the ingest_failures table. |
INGEST_FAILURES_MAX_ROWS |
50000 |
Hard row cap so the table stays bounded under a fleet-wide outage. |
INGEST_FAILURES_DEDUP_MINUTES |
15 |
Repeats of the same (serial, reason, ip) within this window collapse into the first row. |
Both purges run opportunistically on roughly 2% of failure writes.
Oldest agent build whose application usage figures are trusted. A check-in
from an older dated build (YYYY.MM.DD.HHMM) is stored as usual except for
applications.dailyUsageHistory, which is dropped and recorded as a
usage_client_too_old ingest failure at status 200. A missing or non-dated
client version is never judged, so a metadata gap does not drop usage from a
current client.
| Variable | Default | What it does |
|---|---|---|
USAGE_MIN_CLIENT_VERSION |
2026.08.28.0000 |
Floor for macOS and any platform that is not Windows. |
USAGE_MIN_CLIENT_VERSION_WINDOWS |
2026.09.02.0926 |
Floor for Windows. |
| Variable | Default | What it does |
|---|---|---|
CORS_ORIGINS |
empty | Comma-separated allowed origins. Empty means no cross-origin browser access. |
EVENTS_CONNECTION |
unset | Azure Web PubSub connection string for real-time event broadcast and GET /api/v1/negotiate. Without it both degrade gracefully. |
RESPONSE_CACHE_MAX_ENTRIES |
256 |
Ceiling on the in-process response cache. Past it, the oldest entry is evicted first. |
Worth knowing because you may expect a knob and there is not one:
- Event retention is 30 days and idempotency-key retention is 7 days, both hard-coded in
routers/events.pyand purged on roughly 1% of ingests. - Response cache TTLs (15–120s per namespace) are a table in
dependencies.py. Only the entry cap is configurable. - The stale-agent threshold on
/api/v1/installs/filtersis 1 day. - The certificate search hard limit is 10000.
- The "on campus" DNS servers and address prefixes used by
/api/v1/hardwareare constants inrouters/fleet.py. - The application alias map used by the utilization endpoints is a list in
dependencies.py.
AGPL-3.0 — a commercial license is available. reportmate.app