# Copy to .env (dev) or set these in the systemd unit (prod). # PostgreSQL connection (production). Format: # postgresql+psycopg://USER:PASSWORD@HOST:5432/DBNAME DATABASE_URL=postgresql+psycopg://wpsuite:CHANGE_ME@localhost:5432/wpsuite # If DATABASE_URL is omitted entirely, the API falls back to a local SQLite # file (sqlite:///./wpsuite.db) — handy for trying it out without Postgres. # Only needed for CROSS-ORIGIN local development (comma-separated). In # production the site is same-origin via NGINX, so leave this unset. # CORS_ORIGINS=http://localhost:5500 # ── Authentication ──────────────────────────────────────────────────────────── # There is no local password (D15/D16) — Okta OIDC is the only way in. Sign-in # still ends the same way it always did: a signed JWT in an HttpOnly session # cookie, which is what the four vars right below this line are for. The five # OKTA_* vars after that are what makes the actual sign-in possible; without # them the API starts (this is not a hard failure like AUTH_SECRET_KEY), but # describe()'s startup log line says so and nobody can sign in. # Secret used to sign session cookies (JWTs), AFTER Okta has confirmed who # someone is — this app still decides roles/authorization locally, unchanged # by Okta (see server/okta_auth.py). REQUIRED in production: if unset, the API # falls back to a random per-process key, so logins reset on every restart and # break across multiple gunicorn workers. Generate a strong one: # python -c "import secrets; print(secrets.token_urlsafe(48))" AUTH_SECRET_KEY=CHANGE_ME_run_the_command_above # How long a login lasts before re-authentication (hours). Default 12. # AUTH_SESSION_HOURS=12 # ── Okta OIDC (required — this is the only sign-in path) ─────────────────────── # The Okta *authorization server* issuer, e.g. https://yourorg.okta.com/oauth2/default # or a custom authorization server URL. The API discovers the authorize/token/ # jwks endpoints from /.well-known/openid-configuration — nothing # else about Okta's endpoints is hand-entered. OKTA_ISSUER=https://your-org.okta.com/oauth2/default # Client ID and secret from the Okta app integration (Sign-in method: OIDC - # Authorization Code, Application type: Web Application). The secret is exactly # that — treat it like AUTH_SECRET_KEY, never commit it. OKTA_CLIENT_ID=CHANGE_ME OKTA_CLIENT_SECRET=CHANGE_ME # Must exactly match a "Sign-in redirect URI" registered on the Okta app # integration, scheme and path included, e.g.: # https://wp-suite.company.local/api/auth/okta/callback OKTA_REDIRECT_URI=CHANGE_ME # Which ID token claim carries this person's directory identity, matched # against the local users.username column (server/app.py's okta_callback()). # preferred_username is Okta's usual default for an AD-imported user; override # it if your security team's Okta configuration uses a different claim (upn, # a custom claim, …) — no code change needed, just this value. # OKTA_IDENTITY_CLAIM=preferred_username # ── Email notifications (optional) ───────────────────────────────────────────── # WP-assignment emails are OFF by default and are turned on from the Admin # console (Notifications & email card), where the SMTP host/port/from-address # live. The one secret that must NOT be stored in the database — the SMTP # password — is read from this environment variable instead. Leave it unset # until you have the SMTP details; the toggle stays effectively off (queued # notifications are marked "skipped", nothing is sent) until both the toggle is # on and SMTP is configured. # SMTP_PASSWORD=your-smtp-app-password # ── Micron asset catalog (optional) ─────────────────────────────────────────── # Backs the searchable asset picker in the work package creator. READ-ONLY: the # app only ever runs the single SELECT in server/assets_db.py, so give it a # db_datareader login and nothing more. # # Leave this unset and the suite works normally — the picker reports that no # catalog is configured and people type asset tags in by hand. # # URL-encode special characters in the password (@ = %40, # = %23, / = %2F …). # MICRON_DB_URL=mssql+pymssql://readonly_user:PASSWORD@sqlhost.example.com:1433/MicronDB # # To use pyodbc instead of pymssql you must also add pyodbc to requirements.txt # and install the Microsoft ODBC driver in the image: # MICRON_DB_URL=mssql+pyodbc://readonly_user:PASSWORD@sqlhost.example.com/MicronDB?driver=ODBC+Driver+18+for+SQL+Server # # Two things to check when the picker says the catalog is unreachable: # 1. The table/column names in ASSET_QUERY (server/assets_db.py) match the real # Micron schema — that one constant is the whole schema contract. # 2. The api container is on the `outbound` network in docker-compose.yml. The # `internal` network has no default gateway, which blocks the VPN as well as # the internet.