Skip to content

Portal environment variables

Matěj Chalk edited this page Aug 29, 2024 · 3 revisions

The portal is built to be self-hostable by different customers, so its configuration has to be quite flexible to support various infrastructures and cloud providers. This is achieved with a set of (mostly required) environment variables, which need to configured properly to deploy (or locally run) an instance of the portal.

Warning

Some of these environment variables contain secrets (examples below are redacted) which should not be shared with anyone in plain text or hard-coded in any Git repository. For sharing these secrets in chat, use some password manager (e.g. 1Password) or OneTimeSecret. To access them in code, use environment variables (optionally in .env files - should be in .gitignore). To access them in CI/CD pipeline definitions, use the recommended secrets manager, for example:

Environment variables for UI

API_URL

The front-end need this value to know where it's corresponding GraphQL API is hosted for back-end communication.

This variable is used by the NGINX-based Docker image for the portal front-end (europe-docker.pkg.dev/code-pushup/portal/portal-ui). It's used to overwrite the SPA's assets/config.json file when the container starts.

If you're not using the Docker image to serve the front-end, then replacing the apiUrl property in assets/config.json has the same effect. The front-end fetches the config.json when bootstrapping the application, before sending any API requests.

BTW: The API URL also appears in the code-pushup.config.ts in the upload.apiUrl property.

Examples:

  • API_URL=http://localhost:4000 - API served locally
  • API_URL=https://api.code-pushup.example.com/graphql - API instance deployed under customer's own domain
  • API_URL=https://code-pushup-portal-api-clpk79mnpa-ew.a.run.app/graphql - API deployed to Cloud Run (without custom domain)

Environment variables for API

These variables need to be configured to run the API Docker image (europe-docker.pkg.dev/code-pushup/portal/portal-api) or serve the API locally from source.

PORTAL_URL

The back-end needs to know where it's corresponding front-end is hosted, in order to create accurate links to uploaded reports (among other things).

This should be the root URL where users visit the portal (prefer a custom domain if there is one), without any specific paths used within the app (no /login or /portal/... suffixes).

Examples:

  • PORTAL_URL=http://localhost:4200 - front-end served locally (default Angular port)
  • PORTAL_URL=http://localhost:8000 - front-end served locally (another port)
  • PORTAL_URL=https://app.code-pushup.dev - front-end hosted by Code PushUp
  • PORTAL_URL=https://code-pushup.example.com - front-end deployed under customer's own domain
  • PORTAL_URL=https://code-pushup-portal-ui-xafg57nogg-ew.a.run.app - front-end deployed to Cloud Run (without custom domain)

MONGODB_URI and MONGODB_IS_REPLICA_SET

The API needs to know which MongoDB database to connect to, so it expects the MONGODB_URI environment variable to contain a MongoDB connecting string (including user and password if needed). The API also needs to know if it can use transactions (more robust report uploads), which is defined by the MONGODB_IS_REPLICA_SET boolean variable.

The values depend on how you're running MongoDB:

  • MongoDB Atlas is a fully-managed cloud-hosted database with automated scaling and backups, so it the easiest way to deploy and manage MongoDB. Clusters can be deployed to AWS, GCP or Azure and billing may also be managed in another cloud provider using AWS Marketplace, Azure Marketplace or GCP Marketplace.
    • The connection string can be found in the Atlas UI by clicking Connect. It is in the format mongodb+srv://<username>:<password>@<clusterName>.mongodb.net/ (optionally with query params like ?retryWrites=true&w=majority).
    • Atlas uses replica sets, so transactions are supported.
  • The official MongoDB Docker image is useful for running a MongoDB instance locally using Docker, e.g. for testing or demos.
    • The connection string is mongodb://localhost:27017 (if using the default port).
    • No replica sets, so transaction's aren't supported.
  • ... some other options which might be considered in certain use cases: MongoDB Community Edition, MongoDB Enterprise Advanced, Azure Cosmos DB for MongoDB, Amazon DocumentDB

Example for MongoDB Atlas:

MONGODB_URI='mongodb+srv://admin:█████████@code-pushup.7wmil.mongodb.net/?retryWrites=true' # password redacted
MONGODB_IS_REPLICA_SET=true

Example for mongo image from Docker Hub:

MONGODB_URI=mongodb://localhost:27017
MONGODB_IS_REPLICA_SET=false

GITHUB_APP_ID and GITHUB_APP_PRIVATE_KEY

Note

Skip this section if you don't need to integrate any GitHub repositories in your portal instance.

The portal API needs to fetch repository content (branches, commits, etc.) from the Git provider where the project's source code is hosted. For projects hosted on GitHub, read-only access to the GitHub API is needed.

The portal authenticates as a GitHub App. Therefore it requires the app's ID (GITHUB_APP_ID) and private key (GITHUB_APP_PRIVATE_KEY). Both of these can be found/created in the GitHub App's general settings page. The private key variable should contain the multi-line text content of the .pem file.

For self-hosting customers a GitHub App should be created in their organization and given Repository permissions for Contents and Metadata with Read-only access.

Warning

The GitHub App must be installed in every repository which is integrated in the portal. Otherwise the portal will fail to load the project.

Example:

GITHUB_APP_ID=172938
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n████████████████\n-----END RSA PRIVATE KEY-----\n" # redacted

GITLAB_TOKEN and GITLAB_HOST

Note

Skip this section if you don't need to integrate any GitLab projects in your portal instance.

The portal API needs to fetch repository content (branches, commits, etc.) from the Git provider where the project's source code is hosted. For projects hosted on GitLab, read-only access to the GitLab API is needed.

The GITLAB_TOKEN variable should contain an access token with read_api and read_repository scopes. It can be a personal access token, group access token, etc. - more info in GitLab Token overview docs. For private projects, the minimum required role for group/project tokens is Reporter (more info in Permissions and roles - Repository docs).

Warning

The user/group who owns the access token must have access to all GitLab projects integrated in the portal.

For customers with self-hosted GitLab, it is also necessary to specify the domain in the GITLAB_HOST environment variable. If left unspecified, the host is assumed to be https://gitlab.com.

Example with personal access token:

GITLAB_TOKEN=glpat-██████████ # redacted

Example for self-hosted GitLab:

GITLAB_TOKEN=glpat-██████████ # redacted
GITLAB_HOST=https://gitlab.example.com

EMAIL_-prefixed variables

The portal's sign-in flow includes sending an email with a magic link, so an SMTP connection is needed in order to send these emails. Configuration details will depend on which email provider the customer wants to use.

The underlying implementation is in Nodemailer, so refer to SMTP transport docs for what configuration options are available. Environment variables with EMAIL_-prefix are converted into the options object argument to the createTransport function. The EMAIL_-prefix is stripped, UPPER_CASE is converted to camelCase and __ is used to separate nested keys - e.g. EMAIL_AUTH__USER environment variable sets the auth.user property.

An additional EMAIL_SENDER environment variable is supported to set the address emails are sent from. Otherwise, the EMAIL_AUTH__USER environment variable is used as the sender address.

Example for GMail in Google Workspace using service account with domain-wide delegation (in case of problems, set OAuth2 scope to https://mail.google.com/ instead of https://www.googleapis.com/auth/gmail.send):

EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=465
EMAIL_SECURE=true
EMAIL_AUTH__TYPE=OAuth2
EMAIL_AUTH__USER=john.doe@example.com # some email from Google Workspace
EMAIL_AUTH__SERVICE_CLIENT=123456789... # "client_id" of service account
EMAIL_AUTH__PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n████████████████" # "private_key" from service account's .json key, redacted

Example for GMail using App Password:

EMAIL_SERVICE=gmail
EMAIL_AUTH__USER=code.pushup@example.com
EMAIL_AUTH__PASS=████████████████ # 16-character password, redacted

Example for SendGrid with domain authentication or single-sender verification:

EMAIL_SENDER=code.pushup@example.com # authorized single-sender or domain
EMAIL_HOST=smtp.sendgrid.net
EMAIL_PORT=587
EMAIL_AUTH__USER=apikey
EMAIL_AUTH__PASS='SG.████████████████████████████████' # API key from SendGrid with "Mail Send" access

HMAC_SECRET

The portal's authentication flow requires an HMAC secret. It can be any 256-bit key generated by some CSPRNG. It should be unique for each portal instance.

If you have Node installed, then simply execute node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" in your terminal and copy the printed value.

Example:

  • HMAC_SECRET=████████████████████████████████ # 64 hex characters, redacted