7.1 KiB
CLI ops (hivegrid ops)
The operator CLI under packages/cli/ ships three ops sub-commands
for day-to-day operational work:
hivegrid ops doctor— local environment health checkhivegrid ops migrate-tenant— resumable tenant migration between envshivegrid ops impersonate— audit-logged debug magic-link for a tenant user
All three commands accept the --env flag to target a named env file
under ~/.hivegrid/envs/. The default is the current working-dir's
.env (i.e. whatever is already loaded into process.env).
Env-file layout
Named envs live under:
~/.hivegrid/envs/<name>.env
Example layout:
~/.hivegrid/envs/
├── staging.env # chmod 600
├── staging-backup.env
└── dev.env
- File format: standard
KEY=VALUE.envsyntax with#comments. No shell interpolation, no multi-line values. - File permissions must be
0600(owner-only). The CLI emits a warning when world-readable bits are set; rotate the file withchmod 600 ~/.hivegrid/envs/<name>.env. - Production env files must not live in CI. The
impersonatecommand refuses any env namedprod,production, orliveregardless of file content.
hivegrid ops doctor
Runs eight probes against the resolved env and emits an ok/warn/fail table:
| Probe | Description | Fail hint |
|---|---|---|
node.version |
Process Node version >=20 | nvm use |
pnpm.version |
pnpm --version >=9 |
corepack enable |
docker.reachable |
docker info succeeds |
docker compose up -d |
postgres.reachable |
DATABASE_URL ping (injected) | Check docker compose ps postgres |
redis.reachable |
REDIS_URL ping (injected) | docker compose up -d redis |
sentry.dsn |
HEAD against SENTRY_DSN origin | Check Coolify Sentry container |
env.required |
Required env keys present | Update your .env |
prisma.migrations |
prisma migrate status (injected) |
pnpm db:migrate dev |
Examples:
# Default — read local .env
node packages/cli/bin/hivegrid-cli.mjs ops doctor
# Read ~/.hivegrid/envs/staging.env
node packages/cli/bin/hivegrid-cli.mjs ops doctor --env=staging
# JSON output for CI
node packages/cli/bin/hivegrid-cli.mjs ops doctor --json
Exit codes: 0 when every probe is ok or warn; 1 when any
probe reports fail.
Troubleshooting
| Symptom | Likely cause |
|---|---|
postgres.reachable: fail (DATABASE_URL not set) |
Forgot to export .env before running CLI |
docker.reachable: warn |
Docker Desktop not running |
sentry.dsn: warn |
SENTRY_DSN intentionally unset — error reporting disabled |
env.required: fail Missing required env vars: SESSION_SECRET |
Bootstrap your .env from .env.example |
prisma.migrations: warn N pending |
Run pnpm db:migrate dev |
hivegrid ops migrate-tenant
End-to-end tenant migration between named envs. Reuses the
packages/cli/src/commands/tenant/snapshot.ts infrastructure from
phase 03 (#44). Resumable via a state file under
~/.hivegrid/migrations/<tenantId>-<timestamp>.state.json.
Steps (each is an atomic resume-point):
preflight— both envs resolve, names validatedsnapshot—tenant snapshotexports source tenant to a local archiverestore— archive is restored into the target envverify— row-counts compared source vs targetcleanup— snapshot kept on disk for audit
Examples:
# Plan a migration (no writes)
node packages/cli/bin/hivegrid-cli.mjs ops migrate-tenant tenant-abc \
--from=staging --to=staging-backup --dry-run
# Real migration
node packages/cli/bin/hivegrid-cli.mjs ops migrate-tenant tenant-abc \
--from=staging --to=staging-backup
# Resume after a crash
node packages/cli/bin/hivegrid-cli.mjs ops migrate-tenant tenant-abc \
--from=staging --to=staging-backup \
--resume ~/.hivegrid/migrations/tenant-abc-2026-05-17T120000000Z.state.json
The CLI emits a per-step status line:
state-file=/home/op/.hivegrid/migrations/tenant-abc-2026-05-17T120000000Z.state.json
preflight: ok — from=staging to=staging-backup
snapshot: ok — /home/op/.hivegrid/migrations/tenant-abc-….tar.gz
restore: ok — restored 12345 rows
verify: ok — row-counts match
cleanup: ok — snapshot kept on disk for audit
The Prisma + S3 backends are injected at the bin/hivegrid-cli.mjs
entrypoint. The standalone subcommand prints a warning if invoked
without that injection (no destructive operations happen).
hivegrid ops impersonate
Generates a 15-minute HMAC-signed magic-link the engineer can paste
into a browser to debug a specific tenant user. Every issued link
writes an AuditEvent so the action is reviewable.
node packages/cli/bin/hivegrid-cli.mjs ops impersonate \
tenant-abc user-123 \
--env=staging \
--reason="support-ticket-456"
Safety guarantees:
- Production env names (
prod,production,live) are hard-blocked. No--forcebypass exists. Use the admin self-service impersonate UI for production. - TTL is fixed at 15 minutes. Tokens cannot be longer-lived.
- HMAC signing key must be at least 16 characters (the CLI throws otherwise).
- The audit-event captures:
actorType = adminaction = ops.impersonate.issuedtargetType = user,targetId = <userId>regulatoryScope = [soc2]dataSensitivity = piioutcome = successmetadata = { envName, tokenId, expiresAt, ttlMinutes, reason, userEmail }
The audit-event is written before the link is returned, so even a crashing operator workflow leaves a trail.
Backend route
The corresponding loader at
apps/web/app/routes/api.auth.impersonate.tsx (to be wired in a
follow-up phase) is responsible for:
- Verifying the HMAC signature against the same secret
- Looking up the audit-event by
tokenIdand refusing if absent - Refusing if the audit-event's
outcome ≠ success - Setting a session cookie scoped to the impersonated user with a short lifetime
Where things live
packages/cli/src/commands/ops/
├── _env.ts # env-file resolver (local vs named)
├── _env.test.ts
├── doctor.ts # doctor command + 8 probes
├── doctor.test.ts
├── migrate-tenant.ts # 5-step resumable migration
├── migrate-tenant.test.ts
├── impersonate.ts # HMAC magic-link + audit-event
├── impersonate.test.ts
└── index.ts # citty subcommand group
The bin entrypoint in packages/cli/bin/hivegrid-cli.mjs is responsible
for injecting the live Prisma client + S3 client + URL base into the
commands. The standalone files keep zero dependencies on @prisma/client
or AWS SDK so the package builds without optional peers.
Security considerations
- Never commit
~/.hivegrid/envs/*.env. The path is outside the repo on purpose. - The
migrate-tenantstate files contain tenant IDs but no secrets. They are safe to retain for audit. - Snapshot archives may contain PII. Apply the standard PII-retention policy (chmod 600, delete after migration audit window).
- The
impersonateaudit-event is admin-visible and forms part of the soc2 audit trail. Do not redact it after the fact.