mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-14 16:20:03 +00:00
0e40ec07cb
Exercised the full provider portal as a pilot MSP would and fixed what made it feel broken: - The signed-out portal promised "a sign-in link is on the way" even when the control plane has no email provider (the bundle default), and team invitations silently sent nothing. The portal bootstrap now carries email_sign_in_available and provider_hosted_mode; the sign-in page shows the host command that actually prints a link, and the invite panel says invitation emails are not sent and how to hand over a link instead. - New "provider-msp portal-link --email" CLI mints a one-time portal link for an account member or pending invitee, so teammates can sign in at all on email-less installs (bootstrap only covers the owner). - Portal sessions were fixed at 12h; CP_SESSION_TTL now configures them and provider-hosted MSP mode defaults to 7 days. - Creating a client past the license cap showed a generic "Failed to create workspace." toast: the limit error is now a JSON payload with current/limit, the API client no longer drops non-JSON error bodies (double body read), and the toast explains the license limit. - Copy polish: provider-mode sign-in intro (no refunds/privacy register), least-privilege default invite role, queue tile label matches "Client onboarding", softer Support tab with a docs/MSP.md pointer, setup.sh summary now prints the bootstrap next step and day-2 sign-in commands, .env.example and docs/MSP.md document portal sign-in and sessions. Contracts updated (cloud-paid, api-contracts, deployment-installability, security-privacy) with verification pins in tenant_handlers_test, config_test, magiclink_test, and provider_msp_deploy_test. Verified live against a dockerless control plane: portal-link for an invitee redeems, promotes the invitation, and sets a 7-day session; the at-cap toast shows the license copy; portal vitest suite and cloudcp/auth/account/installtests Go suites pass.
138 lines
5.9 KiB
Bash
138 lines
5.9 KiB
Bash
# Domain
|
|
# Client runtimes are routed as https://<client-id>.${DOMAIN}/.
|
|
# Provider-hosted MSP: use the MSP's own domain, for example pulse.example-msp.com.
|
|
# Pulse-hosted MSP: use a Pulse-operated provider namespace, for example example-msp.msp.pulserelay.pro, and set CP_CONTROL_PLANE_MODE=pulse_hosted_msp.
|
|
DOMAIN=msp.example.com
|
|
ACME_EMAIL=admin@example.com
|
|
|
|
# Cloudflare DNS-01 wildcard TLS
|
|
CF_DNS_API_TOKEN=
|
|
|
|
# Image pins; use immutable digest refs in production
|
|
TRAEFIK_IMAGE=traefik@sha256:<pin>
|
|
DOCKER_SOCKET_PROXY_IMAGE=tecnativa/docker-socket-proxy@sha256:<pin>
|
|
CONTROL_PLANE_IMAGE=ghcr.io/rcourtman/pulse-control-plane@sha256:<pin>
|
|
CP_PULSE_IMAGE=ghcr.io/rcourtman/pulse@sha256:<pin>
|
|
|
|
# Control plane
|
|
CP_ENV=production
|
|
CP_CONTROL_PLANE_MODE=provider_hosted_msp
|
|
CP_ADMIN_KEY=
|
|
PULSE_PROVIDER_MSP_DATA_DIR=/data
|
|
PULSE_PROVIDER_MSP_DOCKER_NETWORK=pulse-provider-msp
|
|
PULSE_PROVIDER_MSP_DOCKER_SUBNET=172.30.0.0/24
|
|
PULSE_PROVIDER_MSP_DOCKER_SOCKET=/var/run/docker.sock
|
|
PULSE_PROVIDER_MSP_ROOT_SPACECHECK_DIR=/var/lib/pulse-provider-msp/spacecheck/root
|
|
PULSE_PROVIDER_MSP_DOCKER_SPACECHECK_DIR=/var/lib/docker/.pulse-provider-msp-spacecheck
|
|
CP_TRUSTED_PROXY_CIDRS=172.30.0.0/24
|
|
CP_PROVIDER_MSP_LICENSE_FILE=./provider-msp-license.jwt
|
|
# Entitlement lease signing key. setup.sh generates this; the private key
|
|
# never leaves this host. Your provider MSP license must bind the derived
|
|
# PUBLIC key (entitlement_signing_public_key); print it with
|
|
# `./setup.sh --print-lease-signing-public-key` and include it in your
|
|
# license request. The control plane refuses to start if license and key
|
|
# do not match.
|
|
CP_ENTITLEMENT_SIGNING_PRIVATE_KEY=
|
|
CP_TENANT_MEMORY_LIMIT=536870912
|
|
CP_ALLOW_DOCKERLESS_PROVISIONING=false
|
|
CP_STORAGE_GUARDRAILS_ENABLED=true
|
|
CP_STORAGE_MIN_ROOT_AVAILABLE=10GiB
|
|
CP_STORAGE_MIN_DATA_AVAILABLE=5GiB
|
|
CP_STORAGE_MIN_DOCKER_AVAILABLE=10GiB
|
|
CP_STORAGE_MAX_DOCKER_BUILD_CACHE=2GiB
|
|
CP_PROOF_TENANT_MAX_AGE=24h
|
|
CP_PROOF_TENANT_MATCHERS=proof,canary,rehearsal,msp_prod,ownerseed,owner_seed
|
|
|
|
# Email is optional. Without RESEND_API_KEY the portal cannot send sign-in
|
|
# links or invitation emails; instead, print one-time links on this host:
|
|
# docker compose run --rm control-plane provider-msp bootstrap \
|
|
# --account-name "Example MSP" --owner-email owner@example.com # owner link
|
|
# docker compose run --rm control-plane provider-msp portal-link \
|
|
# --email teammate@example.com # teammate link
|
|
# The portal sign-in page shows the same instructions in this state.
|
|
# Portal sessions last 7 days (CP_SESSION_TTL to change).
|
|
# Set CP_REQUIRE_EMAIL_PROVIDER=true once transactional email is configured.
|
|
CP_REQUIRE_EMAIL_PROVIDER=false
|
|
RESEND_API_KEY=
|
|
PULSE_EMAIL_FROM=noreply@example.com
|
|
PULSE_EMAIL_REPLY_TO=support@example.com
|
|
|
|
# Fresh host setup:
|
|
# sudo -E ./setup.sh
|
|
#
|
|
# Optional one-command setup proof after .env is filled:
|
|
# sudo -E PULSE_PROVIDER_MSP_ACCOUNT_NAME="Example MSP" \
|
|
# PULSE_PROVIDER_MSP_OWNER_EMAIL=owner@example.com \
|
|
# ./setup.sh
|
|
#
|
|
# First owner bootstrap:
|
|
# docker compose run --rm control-plane provider-msp bootstrap \
|
|
# --account-name "Example MSP" \
|
|
# --owner-email owner@example.com
|
|
#
|
|
# Install readiness check:
|
|
# docker compose run --rm control-plane provider-msp preflight
|
|
#
|
|
# Non-mutating operational status:
|
|
# docker compose run --rm control-plane provider-msp status
|
|
#
|
|
# Pre-upgrade / pre-maintenance status gate. This fails unless a verified
|
|
# provider MSP backup archive is available:
|
|
# docker compose run --rm control-plane provider-msp status --require-backup
|
|
#
|
|
# Pre-upgrade / pre-maintenance plan. This is non-mutating and does not pull
|
|
# images:
|
|
# ./upgrade.sh --dry-run
|
|
#
|
|
# Apply a provider control-plane upgrade after updating the image pins in this
|
|
# file. The runner creates and verifies a fresh backup, dry-runs restore into a
|
|
# separate target data dir, pulls provider images, starts Traefik/control-plane,
|
|
# and prints the tenant runtime rollout plan for CP_PULSE_IMAGE:
|
|
# ./upgrade.sh
|
|
#
|
|
# Also roll all client runtimes to the configured CP_PULSE_IMAGE line after the
|
|
# provider services are updated:
|
|
# ./upgrade.sh --rollout-tenants
|
|
#
|
|
# Fresh-install provider proof. This bootstraps the owner account, checks install
|
|
# readiness, creates two proof client workspaces, verifies tenant-local agent
|
|
# ingest and portal handoff, creates and verifies a backup, dry-runs restore and
|
|
# recovery, then removes the proof workspaces.
|
|
# ./run-install-proof.sh \
|
|
# --account-name "Example MSP" \
|
|
# --owner-email owner@example.com
|
|
#
|
|
# Equivalent one-off command:
|
|
# docker compose run --rm control-plane provider-msp install-proof \
|
|
# --account-name "Example MSP" \
|
|
# --owner-email owner@example.com
|
|
#
|
|
# Plan recovery for failed, stuck provisioning, or unhealthy client workspaces:
|
|
# docker compose run --rm control-plane provider-msp recover --all-degraded --dry-run
|
|
#
|
|
# Execute recovery after reviewing the dry-run:
|
|
# docker compose run --rm control-plane provider-msp recover --all-degraded
|
|
#
|
|
# Recovery backup before upgrades or recovery drills:
|
|
# docker compose run --rm control-plane provider-msp backup create
|
|
#
|
|
# Verify a recovery archive before relying on it:
|
|
# docker compose run --rm control-plane provider-msp backup verify \
|
|
# /data/backups/provider-msp/provider-msp-backup-YYYYMMDDTHHMMSSZ.tar.gz
|
|
#
|
|
# Recovery dry-run on a fresh target data directory:
|
|
# docker compose run --rm control-plane provider-msp backup restore \
|
|
# /data/backups/provider-msp/provider-msp-backup-YYYYMMDDTHHMMSSZ.tar.gz \
|
|
# --target-data-dir /data-restore-drill \
|
|
# --dry-run
|
|
#
|
|
# Workspace/runtime proof. This creates two proof client workspaces, generates
|
|
# client-bound agent install tokens, verifies tenant-local agent report ingest,
|
|
# and exercises the portal handoff path. The broader install-proof command above
|
|
# wraps this with preflight, backup, restore dry-run, recovery dry-run, cleanup,
|
|
# and status checks.
|
|
# docker compose run --rm control-plane provider-msp proof \
|
|
# --account-name "Example MSP" \
|
|
# --owner-email owner@example.com \
|
|
# --cleanup
|