wbxcallprov/docker/remote-agent/README.md
jmcqueen 93b060bc8b Modernize bot to Node.js 22 with modular architecture and remote SIW agent
- Refactor monolithic index.js (2646 lines) into src/{webex,integrations,
  cards,flows,commands,services} modules; replace node-fetch/form-data
  with native fetch/FormData; move all secrets to .env via dotenv
- Add dockerized remote SIW agent (docker/remote-agent/) with cross-arch
  buildx packaging (arm64 Mac -> linux/amd64), idempotent install.sh
  deploy bundle, and docker-free ZIP inspector for arch verification
- Bot hosts a WebSocket server; agent proxies SIW requests with a
  per-request insecure:true flag, replacing the process-wide
  NODE_TLS_REJECT_UNAUTHORIZED bypass
- Add ESLint flat config + Prettier, rewrite Dockerfile as non-root
  multi-stage node:22-alpine build, README covering setup / deploy /
  remote agent workflow
- Fix parseStoreArg to read trigger.prompt correctly (was indexing past
  the framework's post-match slice); register /help as regex (string
  matcher only compares the first token); switch catch-all to /.+/
  (previous /.*/gim was stateful due to the g flag); remove
  /fixDisplayNames command and its flow/card

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-06 14:48:51 -04:00

152 lines
6.2 KiB
Markdown

# wbxStoreProvision Remote Agent — Build & Package
This directory produces a self-contained, offline-installable Docker bundle
for the wbxStoreProvision remote agent. The agent is a tiny WebSocket
client that runs inside a segmented (store / on-prem) network and proxies
HTTP requests from the main bot back to Store Info Web.
The layout mirrors the equivalent bundle in the `netanalyzer` repo so the
same operator playbook applies. Both bundles use distinct image tags and
container names (`wbxprov-remote-agent` vs `sha-remote-agent`), so a single
on-prem host can run both agents side by side without conflict.
## Layout
```
docker/remote-agent/
├── Dockerfile build definition (node:22-alpine + tini, non-root)
├── docker-compose.yml build-from-source compose (dev / rebuild use only)
├── package.json the agent's own package manifest (ws + axios + dotenv)
├── package.sh produces the shippable ZIP under dist/
├── inspect-bundle.sh docker-free arch/OS check on any built ZIP
├── remoteAgent.js the agent itself — proxies WS → HTTP
├── .env.example template consumed at deploy time
├── deploy/
│ ├── docker-compose.yml runtime-only compose (used inside the ZIP)
│ ├── install.sh idempotent installer bundled into the ZIP
│ └── README.md operator-facing README bundled into the ZIP
└── dist/ produced by package.sh (git-ignored)
```
## Build & package a bundle
From the repo root, or the `docker/remote-agent/` directory:
```bash
# Default: build for linux/amd64 (typical Rocky/RHEL/Ubuntu servers)
npm run agent:package
# or explicitly: ./docker/remote-agent/package.sh
# ARM Linux target (e.g. Raspberry Pi, ARM-based server)
./docker/remote-agent/package.sh --platform linux/arm64
# Override the version tag
./docker/remote-agent/package.sh --tag 1.0.1
# Preflight only — verify the build environment without actually building.
# Useful the first time you set up a new machine.
npm run agent:check
```
Output: `docker/remote-agent/dist/wbxprov-remote-agent-<version>.zip`.
### How cross-arch builds (arm64 Mac → linux/amd64) are guaranteed
Building an `x86_64` Linux image from an Apple Silicon Mac is the single
easiest way to silently ship a broken bundle, so the script defends against
that in **four independent layers**:
1. **Dedicated `docker-container` builder.** The default buildx builder on
Docker Desktop uses the `docker` driver, which is pinned to the daemon's
native architecture and will happily *ignore* `--platform`. The script
creates (and, if it finds a mis-driver builder with the same name,
*re-creates*) a `wbxprov-remote-agent-builder` using the
`docker-container` driver, which spins up an isolated BuildKit instance
that actually honors `--platform`.
2. **`binfmt` handlers.** When cross-building, the script best-effort
registers QEMU handlers for the target arch via `tonistiigi/binfmt`.
Docker Desktop usually has these; Colima / plain Docker Engine often
don't.
3. **`docker image inspect` check after build.** Reads the image out of the
local daemon and refuses to proceed if `Architecture` doesn't match the
requested `--platform`.
4. **`inspect-bundle.sh` on the final ZIP.** Independent, docker-free check
that reads the image config JSON directly out of the tarball inside the
ZIP. If this passes, the ZIP is provably correct regardless of anything
the local daemon may have said.
If any layer detects a mismatch, `package.sh` exits non-zero and prints
the exact rebuild command. You cannot accidentally ship an arm64 bundle to
an amd64 host.
### Verify a ZIP after the fact (no docker required)
```bash
# Auto-detects the newest ZIP in dist/:
npm run agent:inspect
# Or point it at a specific bundle:
./docker/remote-agent/inspect-bundle.sh path/to/wbxprov-remote-agent-1.0.0.zip
# Enforce expectations (exits non-zero if wrong):
EXPECTED_ARCH=amd64 EXPECTED_OS=linux npm run agent:inspect
```
This works on any machine with `python3` + `unzip` — no Docker daemon
required — so you can verify a bundle on the Linux target host itself
before running `./install.sh`.
### Requirements on the build host
- Docker with the buildx plugin (Docker Desktop includes it out of the box).
- `zip`, `node`, `python3`, and either `sha256sum` or `shasum`.
## Deploy the bundle on the remote host
Transfer the ZIP produced above to the target host, then:
```bash
unzip wbxprov-remote-agent-<version>.zip
cd wbxprov-remote-agent-<version>
./install.sh
```
`install.sh` will:
1. Verify the SHA-256 checksum against `SHA256SUMS`.
2. `docker load` the image tarball.
3. Sanity-check the image architecture matches the host.
4. On first run: copy `.env.example``.env` and stop, asking you to fill
in `WS_URL` (the bot's public WebSocket endpoint) and `WS_TOKEN`
(matching the value in the bot's `.env`).
5. On the second run: `docker compose up -d` to start the container.
See `deploy/README.md` for the full operator-facing guide (upgrades,
troubleshooting, logs).
## Configuring the bot side
The bot's `.env` needs matching values:
```
WS_PORT=8080 # what the bot's WebSocket server listens on
WS_TOKEN=<same secret the agent sends as Authorization: Bearer>
```
Make sure whatever public URL fronts the bot (reverse proxy, ingress, etc.)
maps `/ws` (or wherever `WS_URL` in the agent's `.env` points) through to
`WS_PORT` on the bot container.
## Coexisting with the netanalyzer agent
The two bundles are cleanly separated:
| | wbxStoreProvision | netanalyzer |
| ---------------------- | --------------------------------- | ---------------------------- |
| Image tag | `wbxprov-remote-agent:<version>` | `sha-remote-agent:<version>` |
| Container name | `wbxprov-remote-agent` | `sha-remote-agent` |
| Deploy folder | `wbxprov-remote-agent-<version>/` | `sha-remote-agent-<version>/`|
| `.env` variables | `WS_URL`, `WS_TOKEN` | `WS_URL`, `WS_TOKEN` |
Each has its own `.env` inside its own folder pointing at its own server, so
there's no shared state between them.