[session 1] docs(guide): technical.browser module (#35)
CD - Develop (guide → bcos.dev) / build-and-deploy (push) Has started running

This commit was merged in pull request #35.
This commit is contained in:
2026-07-17 18:17:54 -04:00
parent 0af43b6f78
commit 97f5934d11
2 changed files with 137 additions and 0 deletions
@@ -0,0 +1,50 @@
---
module: technical.browser
title: HiveIQ Browser — Electron desktop client
tab: Gotchas
order: 40
audience: dev
---
# Browser gotchas & diagnostics
## The update check runs at startup only
`checkForBrowserUpdate()` fires once at launch. If a user reports "no update prompt," first confirm
they **restarted** after the new version was published. The result is logged as
`Browser update check result { updateAvailable, latestVersion, currentVersion }` — read that line to
see exactly what their build resolved.
## 2.4.7 / 2.4.8 have a permanently-broken updater
Builds **2.4.7 and 2.4.8** (prod and dev) shipped a broken update checker: `_resolveUpdateChannel`
referenced `authManager` (for the old beta-channel role check), but `authManager` was only
`require`d locally inside `downloadAgent` — so the check threw **`ReferenceError: authManager is not
defined`**, which was swallowed and reported as `updateAvailable: false`. **These builds can never
self-prompt**, for any user/role — the fix (remove the beta channel, remove the dead
`_passesInstitutionGate`) shipped in **2.4.9**. Getting a 2.4.7/2.4.8 user current requires a
**manual reinstall** of 2.4.9 once; auto-update works from there.
Bug introduced in `bca8f60` (2026-06-30, ~10 min before the 2.4.7 build); fixed in `8a5cd3a` + `cfbae6a`.
## "Self signed certificate" on login = DNS, not code
If the browser errors with a self-signed-certificate message, it's almost always a **DNS / `/etc/hosts`
pin** sending it to an internal (self-signed) endpoint instead of the public one — not a code bug.
Check the machine's hosts file / resolver before touching the app.
## Stale refresh token → whitelabel screen on login
An expired/stale refresh token can leave the user on a blank/whitelabel screen at login. Clearing the
stored auth (`clear-auth.sh` locally, or the app's stored tokens) recovers it.
## Same-version re-release doesn't prompt
Re-running the release for an unchanged version number overwrites the installer files but leaves
`latest.json` at the same version — so no client sees an update. Bump the version to trigger auto-update.
## Diagnostics
- Logs: `~/.config/hiveops-browser/logs/` (Linux) / `%APPDATA%/hiveops-browser/logs/` (Windows);
the **dev** build uses `hiveops-browser-dev`.
- `check-license-status.sh`, `clear-auth.sh`, `debug-launch.sh` are handy local helpers in the repo.
@@ -0,0 +1,87 @@
---
module: technical.browser
title: HiveIQ Browser — Electron desktop client
tab: Overview
order: 10
audience: dev
---
# HiveIQ Browser (`hiveops-browser`)
An **Electron** desktop client — a restricted browser that only navigates authorized HiveIQ URLs,
with native license display, agent/software downloads, an in-app feedback form, and self-update.
Distributed as installers from the CDN (**not** a Docker image). Current line: `2.x` (2.4.9).
## Build variants — prod vs dev
The same codebase produces two isolated builds, selected by `BUILD_VARIANT` (`src/main/config.js`):
- Resolved from `HIVEOPS_BUILD_VARIANT` env (local `npm start` override) → else
`package.json.buildVariant` (injected at package time via electron-builder `extraMetadata`) → else **`prod`**.
- **prod** (`electron-builder.yml`, `npm run build`) → points at `*.bcos.cloud`, config `config/prod.config.json`.
- **dev** (`build-dev.sh` + `electron-builder.dev.yml`, `extraMetadata.buildVariant=dev`) → points at
`*.bcos.dev`, config `config/dev.config.json`, output `dist-dev/`.
- The dev build gets a **separate OS identity** (`app.setName('hiveops-browser-dev')` → its own
`userData`, single-instance lock, protocol registration) so dev and prod can run side by side.
- **Safety:** in the dev build, `assertNoProdUrls()` refuses to start if any resolved config value
contains `bcos.cloud` (sets `global.DEV_CONFIG_ERROR`).
## Config resolution (`src/main/config.js`)
`loadProfileConfig()` reads the active profile JSON (`prod.config.json` / `dev.config.json`); the dev
build merges over a `devSafeBase` (no prod URLs), the prod build over `defaultConfig`. `config.get(key)`
re-reads the profile file for URL keys (`apiBaseUrl`, `authServerUrl`, `allowedUrl`, `browserUpdatePath`,
the per-app base URLs) so switching profiles takes effect without code changes. `releaseServerUrl` also
honors a user override stored in `electron-store`.
Two client-shipped tokens live in config.js (not repo/Gitea creds): `FEEDBACK_SUBMIT_KEY` (write-only
feedback submit) and `CDN_TOKEN` (gated `/downloads/software/` + `/downloads/hotfix/`); both overridable
by env for rotation.
## Auth — two clients, MFA lives in `hiveops-auth`
`src/main/api-client.js` builds **two** axios instances, and **every** request from both carries
`X-HiveIQ-Browser-Version: <app.getVersion()>` (plus `X-HiveIQ-Browser: true`):
- `getClient()` → `apiBaseUrl` (mgmt, `/mgmt/api/v1`). Its `login()` posts to `/auth/login`.
- `getAuthClient()` → `authServerUrl` + `/api` (hiveops-auth). **This is the real customer/MSP login
path**: `authLogin()` → optional MFA (`authVerifyMfa`, `authVerifyBackupCode`) → tokens. TOTP/backup
MFA is enforced by `hiveops-auth`.
Because the version header is on every login, the backend can capture it — see the browser-version
tracking on the mgmt portal (`technical.mgmt`) and MSP users list (`technical.auth` `/msp/users`).
## Self-update
`checkForBrowserUpdate()` runs **at startup** (not a background timer):
1. `_resolveUpdateChannel()` fetches the **general channel** manifest —
`${releaseServerUrl}${browserUpdatePath}/latest.json` (prod `cdn.bcos.cloud/downloads/browser`,
dev `cdn.bcos.dev/browser-dev`). **Beta/pre-release channels were removed** (2.4.9) — every user
updates from the one general channel.
2. `_isNewer(latest, current)` (semver-ish) decides; if newer, prompt.
3. Download from `${releaseServerUrl}/downloads/<filename>`.
Because the check is **startup-only**, a user must restart to pick up a new version.
## Menus & windows (`src/main/main.js`)
- **Software** menu (Download Agent / Upload Hotfix / Upload Software) is shown **only to MSP_ADMIN /
BCOS_ADMIN**.
- **Help → About** (Info / License / Usage / Disclaimers tabs; License shows Status/Tier/masked
Key/Expires/Days-Remaining via `getLicenseInfo()`) and **Feedback** open as **modal** windows.
- Feedback form (`src/renderer/feedback.html`) offers Bug / Enhancement / Documentation / Incident
types with per-type templates, and stamps `reporterUserId` from the JWT `sub`; submits to
`<gateway>/feedback/api/submit` (see `technical.feedback`). "What's New" popup was removed.
## Release (CI is broken — build locally)
`release.yml` tag-trigger fails, so releases are cut **locally** with electron-builder:
- **Prod:** `npm run build:win` / `build:linux` → scp installers to CDN VM `173.231.195.252` →
`release-browser.sh <version> <exe> <deb>` (writes `downloads/browser/latest.json`).
- **Dev:** `build-dev.sh` → scp to `173.231.195.251` under `downloads/downloads/` →
`release-browser-dev.sh`.
- Re-releasing the **same version** overwrites files but does not bump the manifest → no auto-update prompt.
See **`technical.browser` Gotchas** for the update-channel failure modes and the self-signed-cert red herring.