RedlineKnowledge base

Redline local QA

Run Redline’s QA environment on any computer that is on the tailnet and can reach the GitLab API, published at https://qa-yqa.fio.sh through a Cloudflare Tunnel. It runs the verified image: the build CI promotes automatically from main, before anyone releases it.

Reader → Cloudflare (Access) → qa-yqa.fio.sh → tunnel → cloudflared container
       → service container (dashboard + /v1, one origin)
service container → https://glab.fio.sh over the computer's Tailscale connection

Two containers and one settings file. There is no database: GitLab stores every comment and history record, sessions are encrypted cookies, and caches live in memory.

What you need

  • Docker (Docker Desktop on macOS), Node 22 and this repository checked out.
  • Tailscale connected, so the computer reaches https://glab.fio.sh.
  • cloudflared on the computer (macOS: brew install cloudflared), and access to the Cloudflare account for fio.sh.
  • In GitLab: the Fridai Redline OAuth application (administrator), a token with read_api, and a token with read_registry to pull the image.

1. GitLab values

  1. OAuth application. In Admin > Applications > Fridai Redline, add https://qa-yqa.fio.sh/v1/auth/gitlab/callback as a line under Redirect URI (keep the existing lines). Confidential, scope api. Note the Application ID and the secret.

  2. Read token. A group access token on fridai (or a project token on fridai/fio-dep/fio-redline), role Reporter, scope read_api only.

  3. Registry login, once per computer, with a read_registry token:

    docker login glab.fio.sh:5050 --username <your GitLab username>

2. Tunnel and DNS

cloudflared tunnel login          # browser: choose the fio.sh zone
npm run qa:local -- tunnel

The second command creates the tunnel fio-redline-qa, adds the DNS record qa-yqa.fio.sh pointing at it, writes the ingress to ops/local-qa/cloudflared/config.yml, and stores the tunnel token in ops/local-qa/cloudflared.env. Both files stay out of git. To use another name, set QA_HOSTNAME for this and every later command.

3. Cloudflare Access

A tunnel hostname is public. Put it behind Access before anyone else learns the address: in Cloudflare Zero Trust, Access > Applications > Add an application > Self-hosted, domain qa-yqa.fio.sh, with the same allow policy as yqa.fio.sh. The service does not read Access identities (it runs in gitlab-oauth mode); Access only gates the edge. Readers then connect GitLab as usual, which needs Tailscale because glab.fio.sh is on the tailnet.

For scripted checks, create an Access service token and allow it in the application’s policy; see section 5.

4. Start

npm run qa:local -- up

Run it in your own terminal. The first run creates the settings file (ops/local-qa/qa.env, readable only by you), generates the session, draft-signing and webhook secrets, and then asks for the three GitLab values from section 1: the read token (checked against GitLab before it is saved), the OAuth Application ID and its secret. Secrets are not shown as you type, and nothing is saved if you cancel. It then pulls the image, starts both containers, waits for health, runs the smoke check against http://127.0.0.1:18787, and reports whether the public address is behind Access.

To change the GitLab values later (a new token, a rotated secret), run npm run qa:local -- configure.

Other commands: npm run qa:local -- status, -- logs, -- down. To update to the newest verified build, run up again (it pulls first).

5. Check it

In a browser on the tailnet: open https://qa-yqa.fio.sh/, sign in through Access, open a page under Knowledge base, and connect GitLab from the comments panel.

From a terminal, with an Access service token in the environment:

export CF_ACCESS_CLIENT_ID=<service token client id>
export CF_ACCESS_CLIENT_SECRET=<service token secret>
npm run smoke -- https://qa-yqa.fio.sh fio-redline kb/index.md
REDLINE_LIVE_URL=https://qa-yqa.fio.sh npm run test:live

Set those two variables in your shell from your password manager, not as part of a command line that history records.

Differences from the GitLab-host QA

  • GitLab cannot send webhooks to this computer, so pages pick up new commits and comments when the service cache expires (within about a minute).
  • The address is reachable off the tailnet through Cloudflare, behind Access. The tailnet still gates the GitLab sign-in.
  • The environment runs while the computer and its Tailscale connection are up.

Troubleshooting

  • status reports a TLS error for the public address. On the free plan, Cloudflare’s Universal SSL certificate covers fio.sh and first-level names (*.fio.sh) only, which is why QA is qa-yqa.fio.sh and not qa.yqa.fio.sh. If you choose another QA_HOSTNAME, keep it first-level (one label before fio.sh) and add its callback URI to the OAuth application. A new record can take a few minutes to get its certificate.
  • The service is unhealthy and the logs show gitlab-unreachable. Tailscale is not connected, or the computer cannot reach https://glab.fio.sh.
  • pull fails. Run docker login glab.fio.sh:5050 again; the read_registry token may have expired.
  • GitLab reports a redirect URI mismatch. The callback on the OAuth application must equal https://<QA_HOSTNAME>/v1/auth/gitlab/callback exactly.