From ee63d438ccabafd501c62b89ebcf3017cb550e6f Mon Sep 17 00:00:00 2001 From: rcourtman Date: Tue, 20 Jan 2026 09:43:49 +0000 Subject: [PATCH] docs: standardize markdown syntax and remove deprecated sensor-proxy docs --- .devcontainer/README.md | 10 ++-- .github/ISSUE_TEMPLATE/bug_report.md | 6 +- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- .markdownlint-cli2.jsonc | 10 ++++ .markdownlint.json | 25 ++++++++ ARCHITECTURE.md | 4 +- CONTRIBUTING.md | 8 +++ README.md | 3 +- SECURITY.md | 10 ++-- cmd/pulse-sensor-proxy/README.md | 6 +- docs/AI.md | 2 +- docs/API.md | 20 +++++-- docs/CONFIGURATION.md | 29 +++++----- docs/DEPLOYMENT_MODELS.md | 2 - docs/FAQ.md | 2 +- docs/INSTALL.md | 1 + docs/KUBERNETES.md | 24 ++++---- docs/METRICS_HISTORY.md | 6 +- docs/OIDC.md | 36 ++++++------ docs/PROXY_AUTH.md | 2 +- docs/PROXY_CONTROL_PLANE.md | 43 -------------- docs/README.md | 9 +-- docs/RELEASE_NOTES.md | 3 +- docs/SECURITY_CHANGELOG.md | 8 +-- docs/TEMPERATURE_MONITORING.md | 20 +++---- docs/TROUBLESHOOTING.md | 20 +++---- docs/UNIFIED_AGENT.md | 2 - docs/VM_DISK_MONITORING.md | 4 +- docs/api/SCHEDULER_HEALTH.md | 17 +----- docs/monitoring/ADAPTIVE_POLLING.md | 22 +++---- docs/monitoring/PROMETHEUS_METRICS.md | 11 +++- docs/operations/ADAPTIVE_POLLING_ROLLOUT.md | 14 ++--- docs/operations/AUDIT_LOG_ROTATION.md | 54 ----------------- docs/operations/AUTO_UPDATE.md | 1 + docs/operations/SENSOR_PROXY_CONFIG.md | 44 -------------- docs/operations/SENSOR_PROXY_LOGS.md | 35 ----------- docs/releases/RELEASE_NOTES_v4.md | 32 +++++------ docs/security/SENSOR_PROXY_APPARMOR.md | 47 --------------- docs/security/SENSOR_PROXY_HARDENING.md | 64 --------------------- docs/security/SENSOR_PROXY_NETWORK.md | 39 ------------- docs/security/TEMPERATURE_MONITORING.md | 19 +++--- internal/api/DO_NOT_EDIT_FRONTEND_HERE.md | 6 +- internal/api/README.md | 2 +- tests/integration/QUICK_START.md | 14 ++--- tests/integration/README.md | 2 +- 45 files changed, 228 insertions(+), 512 deletions(-) create mode 100644 .markdownlint-cli2.jsonc create mode 100644 .markdownlint.json delete mode 100644 docs/PROXY_CONTROL_PLANE.md delete mode 100644 docs/operations/AUDIT_LOG_ROTATION.md delete mode 100644 docs/operations/SENSOR_PROXY_CONFIG.md delete mode 100644 docs/operations/SENSOR_PROXY_LOGS.md delete mode 100644 docs/security/SENSOR_PROXY_APPARMOR.md delete mode 100644 docs/security/SENSOR_PROXY_HARDENING.md delete mode 100644 docs/security/SENSOR_PROXY_NETWORK.md diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 60da91c1d..5f5a01a0e 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -51,9 +51,9 @@ pd # Alias for ./scripts/hot-dev.sh Or use VS Code task: `Cmd+Shift+P` → "Tasks: Run Task" → "Start Pulse Dev Server" **Access the app:** -- Frontend: http://localhost:7655 -- Backend API: http://localhost:7656 -- Metrics: http://localhost:9091 +- Frontend: +- Backend API: +- Metrics: ## Development Workflows @@ -66,7 +66,7 @@ Or use VS Code task: `Cmd+Shift+P` → "Tasks: Run Task" → "Start Pulse Dev Se **Backend (3-5 seconds):** - Edit any `.go` file - Save → Terminal shows: - ``` + ```text 🔄 Change detected: yourfile.go Rebuilding backend... ✓ Build successful, restarting backend... @@ -241,7 +241,7 @@ Custom overrides: Create `.env.devcontainer` (gitignored) ## Architecture -``` +```text MacBook (VS Code) ↓ Remote-SSH dev-containers VM (Proxmox) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index ab3c64c6f..cc216381f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -20,10 +20,10 @@ Steps to reproduce the behavior: What you expected to happen. **Environment:** - - Pulse Version: [e.g. v4.15.0] - - Installation Type: [e.g. ProxmoxVE LXC, Docker, Manual] +- Pulse Version: [e.g. v4.15.0] +- Installation Type: [e.g. ProxmoxVE LXC, Docker, Manual] **Additional context** Add any other context, screenshots, or logs here. -💡 **Tip:** If you're experiencing connection issues, API errors, or missing data, you can attach diagnostics from Settings → Diagnostics tab → Export for GitHub (sanitized version) \ No newline at end of file +💡 **Tip:** If you're experiencing connection issues, API errors, or missing data, you can attach diagnostics from Settings → Diagnostics tab → Export for GitHub (sanitized version) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 64118e9de..36014cde5 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -17,4 +17,4 @@ A clear and concise description of what you want to happen. A clear and concise description of any alternative solutions or features you've considered. **Additional context** -Add any other context or screenshots about the feature request here. \ No newline at end of file +Add any other context or screenshots about the feature request here. diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc new file mode 100644 index 000000000..b2b21e2f4 --- /dev/null +++ b/.markdownlint-cli2.jsonc @@ -0,0 +1,10 @@ +{ + "config": ".markdownlint.json", + "globs": [ + "**/*.md" + ], + "ignores": [ + "**/node_modules/**", + ".agent/workflows/hot-dev.md" + ] +} diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 000000000..3771bf3c9 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,25 @@ +{ + "MD013": false, + "MD029": { + "style": "ordered" + }, + "MD022": false, + "MD030": false, + "MD031": false, + "MD032": false, + "MD060": false, + "MD033": { + "allowed_elements": [ + "br", + "details", + "div", + "h1", + "h2", + "h3", + "img", + "p", + "summary", + "strong" + ] + } +} diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index db8716be5..068fd0a22 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -75,9 +75,7 @@ The frontend is a modern Single Page Application (SPA) built with **SolidJS** an * **Vite**: For fast development and optimized builds. ### State Management -* **Stores (`frontend-modern/src/stores`)**: - * `websocket.ts`: The central nervous system. It maintains the WS connection, handles reconnection logic, and updates reactive signals when new data arrives. - * `metricsHistory.ts`: Buffers incoming metrics to drive historical charts (Sparklines) without needing a time-series database backend. +* **Stores (`frontend-modern/src/stores`)**: `websocket.ts` manages the WS connection and reactive updates; `metricsHistory.ts` buffers metrics for sparklines. ### Component Design * **Atomic Design**: Small, reusable components (`MetricBar`, `StatusBadge`) compose into larger views (`NodeSummaryTable`). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a35147a65..f8a1b0240 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,6 +43,14 @@ cd .. npm run mock:on # Optional: enable mock data ``` +Backend-only hot reload (requires `air`): + +```bash +air -c .air.toml +``` + +Set `HOT_DEV_USE_PRO=true` to build the Pro variant when available. + Mock mode is supported for development, but the internal developer notes are not shipped in this repository. --- diff --git a/README.md b/README.md index 866f5db53..b833ca823 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ +# Pulse +
Pulse Logo -

Pulse

Real-time monitoring for Proxmox, Docker, and Kubernetes infrastructure.

[![GitHub Stars](https://img.shields.io/github/stars/rcourtman/Pulse?style=flat&logo=github)](https://github.com/rcourtman/Pulse) diff --git a/SECURITY.md b/SECURITY.md index 8577a4fd1..ceec98fc4 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -70,7 +70,7 @@ docker exec pulse rm -rf /home/pulse/.ssh/id_ed25519* #### Security Boundary -``` +```text ┌─────────────────────────────────────┐ │ Proxmox Host │ │ ┌───────────────────────────────┐ │ @@ -112,9 +112,9 @@ Verify temperature collection is agent-based: journalctl -u pulse-agent -n 200 --no-pager ``` -**Documentation:** https://github.com/rcourtman/Pulse/blob/main/SECURITY.md#critical-security-notice-for-container-deployments -**Issues:** https://github.com/rcourtman/pulse/issues -**Private disclosures:** security@pulseapp.io +**Documentation:** +**Issues:** +**Private disclosures:** --- @@ -239,7 +239,7 @@ docker run -e ALLOW_UNPROTECTED_EXPORT=true rcourtman/pulse:latest **Note:** for production, prefer Docker secrets or systemd environment files for sensitive data. -## Security Features +## Security Features Summary ### Core Protection - **Encryption**: credentials encrypted at rest (AES-256-GCM) diff --git a/cmd/pulse-sensor-proxy/README.md b/cmd/pulse-sensor-proxy/README.md index da7004729..83ff1ba52 100644 --- a/cmd/pulse-sensor-proxy/README.md +++ b/cmd/pulse-sensor-proxy/README.md @@ -150,10 +150,10 @@ all HTTP access attempts to the audit log. - Format: JSON with hash chaining (`prev_hash`, `event_hash`, `seq`) - Access: Owned by `pulse-sensor-proxy`, `0640`, `chattr +a` -Follow `docs/operations/AUDIT_LOG_ROTATION.md` for rotation (remove `+a`, +Follow standard log rotation practices (e.g., `logrotate`) for rotation (remove `+a`, truncate, restart service, reapply `+a`). Also consider forwarding with `scripts/setup-log-forwarding.sh`; see -`docs/operations/SENSOR_PROXY_LOGS.md` for log forwarding and verification +See standard rsyslog practices for log forwarding and verification. steps. ## Metrics & Monitoring @@ -234,5 +234,5 @@ If you suspect config corruption (service won't start, temperatures stopped): sudo systemctl start pulse-sensor-proxy ``` -For additional hardening steps, read `docs/security/SENSOR_PROXY_HARDENING.md` and +For additional hardening steps, read the main `docs/security/TEMPERATURE_MONITORING.md` guide and `docs/security/TEMPERATURE_MONITORING.md`. diff --git a/docs/AI.md b/docs/AI.md index d082ac578..b2ae2b769 100644 --- a/docs/AI.md +++ b/docs/AI.md @@ -1,6 +1,6 @@ # Pulse AI -Pulse Pro unlocks **AI Patrol** for continuous, automated health checks. Learn more at https://pulserelay.pro or see the technical overview in [PULSE_PRO.md](PULSE_PRO.md). +Pulse Pro unlocks **AI Patrol** for continuous, automated health checks. Learn more at or see the technical overview in [PULSE_PRO.md](PULSE_PRO.md). ## What Patrol Actually Does (Technical) diff --git a/docs/API.md b/docs/API.md index 55aff71c2..3deca604d 100644 --- a/docs/API.md +++ b/docs/API.md @@ -8,18 +8,18 @@ Pulse provides a comprehensive REST API for automation and integration. Most API requests require authentication via one of the following methods: -**1. API Token (Recommended)** +### API Token (Recommended) Pass the token in the `X-API-Token` header. ```bash curl -H "X-API-Token: your-token" http://localhost:7655/api/health ``` -**2. Bearer Token** +### Bearer Token ```bash curl -H "Authorization: Bearer your-token" http://localhost:7655/api/health ``` -**3. Session Cookie** +### Session Cookie Standard browser session cookie (used by the UI). Public endpoints include: @@ -54,6 +54,18 @@ Returns the complete state of your infrastructure (Nodes, VMs, Containers, Stora ### Version Info `GET /api/version` Returns version, build time, and update status. +Example response: +```json +{ + "version": "5.0.16", + "buildTime": "2026-01-19T22:20:18Z", + "channel": "stable", + "deploymentType": "systemd", + "updateAvailable": true, + "latestVersion": "5.0.17" +} +``` +Version fields are returned as plain semantic versions (no leading `v`). --- @@ -312,7 +324,7 @@ Returns scheduler health, DLQ, and breaker status. Requires `monitoring:read`. - `POST /api/updates/apply` - `GET /api/updates/status` - `GET /api/updates/stream` -- `GET /api/updates/plan?version=vX.Y.Z` (optional `channel`) +- `GET /api/updates/plan?version=X.Y.Z` (optional `channel`, accepts `v` prefix) - `GET /api/updates/history` - `GET /api/updates/history/entry?id=` diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md index ec95687f7..edfd8a867 100644 --- a/docs/CONFIGURATION.md +++ b/docs/CONFIGURATION.md @@ -3,7 +3,7 @@ Pulse uses a split-configuration model to ensure security and flexibility. | File | Purpose | Security Level | -|------|---------|----------------| +| ------ | --------- | ---------------- | | `.env` | Authentication & Secrets | 🔒 **Critical** (Read-only by owner) | | `.encryption.key` | Encryption key for `.enc` files | 🔒 **Critical** | | `system.json` | General Settings | 📝 Standard | @@ -36,6 +36,8 @@ Pulse uses a split-configuration model to ensure security and flexibility. | `ai_remediations.json` | AI remediation suggestions | 📝 Standard | | `ai_incidents.json` | AI incident tracking | 📝 Standard | +Guest metadata entries are keyed by the canonical guest ID format `instance:node:vmid` (for example, `pve1:node1:100`). Legacy dash-separated keys are migrated automatically. + All files are located in `/etc/pulse/` (Systemd) or `/data/` (Docker/Kubernetes) by default. Path overrides: @@ -85,7 +87,7 @@ See [OIDC Documentation](OIDC.md) and [Proxy Auth](PROXY_AUTH.md) for details. Environment overrides (lock the corresponding UI fields): | Variable | Description | -|----------|-------------| +| ---------- | ------------- | | `OIDC_ENABLED` | Enable OIDC (`true`/`false`) | | `OIDC_ISSUER_URL` | Issuer URL from your IdP | | `OIDC_CLIENT_ID` | Client ID | @@ -101,6 +103,7 @@ Environment overrides (lock the corresponding UI fields): | `OIDC_ALLOWED_EMAILS` | Allowed emails (space or comma-separated) | | `OIDC_GROUP_ROLE_MAPPINGS` | Group-to-role mappings (Pro). Format: `group1=role1,group2=role2` | | `OIDC_CA_BUNDLE` | Custom CA bundle path | + > **Note**: `API_TOKEN` / `API_TOKENS` are legacy and will be migrated into `api_tokens.json` on startup. @@ -138,7 +141,7 @@ Controls runtime behavior like ports, logging, and polling intervals. Most of th Environment variables take precedence over `system.json`. | Variable | Description | Default | -|----------|-------------|---------| +| ---------- | ------------- | --------- | | `FRONTEND_PORT` | Public listening port | `7655` | | `PORT` | Legacy alias for `FRONTEND_PORT` | *(unset)* | | `BACKEND_HOST` | Bind host for the HTTP server and metrics listener (advanced) | *(unset)* | @@ -149,7 +152,7 @@ Environment variables take precedence over `system.json`. #### Log Levels | Level | Description | -|-------|-------------| +| ------- | ------------- | | `error` | Only errors and critical issues | | `warn` | Errors + warnings (recommended for minimal logging) | | `info` | Standard operational messages (startup, connections, alerts) | @@ -158,7 +161,7 @@ Environment variables take precedence over `system.json`. > **Tip**: If your syslog is being flooded with Pulse messages, set `LOG_LEVEL=warn` to significantly reduce log volume while still capturing important events. | Variable | Description | Default | -|----------|-------------|---------| +| ---------- | ------------- | --------- | | `PULSE_PUBLIC_URL` | URL for UI links, notifications, and OIDC. For reverse proxies, keep this as the public URL and use `PULSE_AGENT_CONNECT_URL` for agent installs if you need a direct/internal address. | Auto-detected | | `PULSE_AGENT_CONNECT_URL` | Dedicated direct URL for agents (overrides `PULSE_PUBLIC_URL` for agent install commands). Alias: `PULSE_AGENT_URL`. | *(unset)* | | `PULSE_AGENT_CONFIG_SIGNING_KEY` | Base64 Ed25519 private key used to sign remote agent config payloads. | *(unset)* | @@ -195,7 +198,7 @@ When `allowEmbedding` is `false`, Pulse sends `X-Frame-Options: DENY` and `frame ### Monitoring Overrides | Variable | Description | Default | -|----------|-------------|---------| +| ---------- | ------------- | --------- | | `PVE_POLLING_INTERVAL` | PVE metrics polling frequency | `10s` | | `PBS_POLLING_INTERVAL` | PBS metrics polling frequency | `60s` | | `PMG_POLLING_INTERVAL` | PMG metrics polling frequency | `60s` | @@ -222,7 +225,7 @@ When `allowEmbedding` is `false`, Pulse sends `X-Frame-Options: DENY` and `frame ### Logging Overrides | Variable | Description | Default | -|----------|-------------|---------| +| ---------- | ------------- | --------- | | `LOG_FILE` | Log file path (empty = stdout) | *(unset)* | | `LOG_MAX_SIZE` | Log file max size (MB) | `100` | | `LOG_MAX_AGE` | Log file retention (days) | `30` | @@ -233,7 +236,7 @@ When `allowEmbedding` is `false`, Pulse sends `X-Frame-Options: DENY` and `frame These are stored in `system.json` and managed via the UI. | Key | Description | Default | -|-----|-------------|---------| +| ----- | ------------- | --------- | | `updateChannel` | Update channel (`stable` or `rc`) | `stable` | | `autoUpdateEnabled` | Allow one-click updates | `false` | | `autoUpdateCheckInterval` | Stored UI preference (server currently checks hourly) | `24` | @@ -244,7 +247,7 @@ These are stored in `system.json` and managed via the UI. You can auto-import an encrypted backup on first startup. This is useful for automated provisioning and test environments. | Variable | Description | -|----------|-------------| +| ---------- | ------------- | | `PULSE_INIT_CONFIG_DATA` | Base64 or raw contents of an export bundle (auto-imports on first start) | | `PULSE_INIT_CONFIG_FILE` | Path to an export bundle on disk (auto-imports on first start) | | `PULSE_INIT_CONFIG_PASSPHRASE` | Passphrase for the export bundle (required) | @@ -256,7 +259,7 @@ You can auto-import an encrypted backup on first startup. This is useful for aut These are primarily for development or test harnesses and should not be used in production. | Variable | Description | Default | -|----------|-------------|---------| +| ---------- | ------------- | --------- | | `PULSE_UPDATE_SERVER` | Override update server base URL (testing only) | *(unset)* | | `PULSE_UPDATE_STAGE_DELAY_MS` | Adds artificial delays between update stages (testing only) | *(unset)* | | `PULSE_ALLOW_DOCKER_UPDATES` | Expose update UI/actions in Docker (debug only) | `false` | @@ -339,7 +342,7 @@ API tokens provide scoped, revocable access to Pulse. Manage tokens in **Setting ### Token Scopes | Scope | Description | -|-------|-------------| +| ------- | ------------- | | `*` (Full access) | All permissions (legacy, not recommended) | | `monitoring:read` | View dashboards, metrics, alerts | | `monitoring:write` | Acknowledge/silence alerts | @@ -356,7 +359,7 @@ API tokens provide scoped, revocable access to Pulse. Manage tokens in **Setting The UI offers quick presets for common use cases: | Preset | Scopes | Use Case | -|--------|--------|----------| +| -------- | -------- | ---------- | | **Kiosk / Dashboard** | `monitoring:read` | Read-only dashboard displays | | **Host agent** | `host-agent:report` | Host agent authentication | | **Container report** | `docker:report` | Container agent (read-only) | @@ -372,7 +375,7 @@ For unattended displays (wall monitors, dashboards), use a kiosk token to avoid 2. Click **New token** and select the **Kiosk / Dashboard** preset 3. Copy the generated token 4. Access Pulse via URL with token: - ``` + ```text https://your-pulse-url/?token=YOUR_TOKEN_HERE ``` diff --git a/docs/DEPLOYMENT_MODELS.md b/docs/DEPLOYMENT_MODELS.md index dbb66dcdf..9701c5ce6 100644 --- a/docs/DEPLOYMENT_MODELS.md +++ b/docs/DEPLOYMENT_MODELS.md @@ -65,7 +65,6 @@ Pull a new image and restart: docker pull rcourtman/pulse:latest docker compose up -d ``` - ### Kubernetes (Helm) Upgrade the chart: @@ -74,4 +73,3 @@ Upgrade the chart: helm repo update helm upgrade pulse pulse/pulse -n pulse ``` - diff --git a/docs/FAQ.md b/docs/FAQ.md index 892293c5b..36048884e 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -42,7 +42,7 @@ If a setting is disabled with an amber warning, it's being overridden by an envi Pulse Pro unlocks **AI Patrol** — scheduled, cross-system analysis that correlates real-time state, recent metrics history, and diagnostics to surface actionable findings. Example output includes trend-based capacity warnings, backup regressions, Kubernetes AI cluster analysis, and correlated container failures that simple threshold alerts miss. -See [AI Patrol](AI.md), [Pulse Pro technical overview](PULSE_PRO.md), and https://pulserelay.pro. +See [AI Patrol](AI.md), [Pulse Pro technical overview](PULSE_PRO.md), and . ### Why do VMs show "-" for disk usage? Proxmox API returns `0` for VM disk usage by default. You must install the **QEMU Guest Agent** inside the VM and enable it in Proxmox (VM → Options → QEMU Guest Agent). diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 91b7bb755..46f556a20 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -143,6 +143,7 @@ Pulse can self-update to the latest stable version. **Enable via UI**: Settings → System → Updates ### Manual Update + | Platform | Command | |----------|---------| | **Docker** | `docker pull rcourtman/pulse:latest && docker restart pulse` | diff --git a/docs/KUBERNETES.md b/docs/KUBERNETES.md index 29dd1546f..d8e41d295 100644 --- a/docs/KUBERNETES.md +++ b/docs/KUBERNETES.md @@ -4,9 +4,9 @@ This guide explains how to deploy the Pulse Server (Hub) and Pulse Agents on Kub ## Prerequisites -* A Kubernetes cluster (v1.19+) -* `helm` (v3+) installed locally -* `kubectl` configured to talk to your cluster +- A Kubernetes cluster (v1.19+) +- `helm` (v3+) installed locally +- `kubectl` configured to talk to your cluster ## 1. Deploying the Pulse Server @@ -42,7 +42,7 @@ helm template pulse pulse/pulse \ --namespace pulse \ --set persistence.enabled=true \ > pulse-server.yaml -``` +```text You can then apply this file: @@ -126,11 +126,11 @@ Use a token scoped for the agent: #### Important DaemonSet Configuration -**PULSE_AGENT_ID (Required for DaemonSets)** +##### PULSE_AGENT_ID (Required for DaemonSets) When running as a DaemonSet, all pods share the same API token but need a unified identity. Without `PULSE_AGENT_ID`, each pod auto-generates a unique ID (e.g., `mac-xxxxx`), causing token conflicts: -``` +```text API token is already in use by agent "mac-aa5496fed726". Each Kubernetes agent must use a unique API token. ``` @@ -141,7 +141,7 @@ Set `PULSE_AGENT_ID` to a shared cluster name so all pods report as one logical value: "my-k8s-cluster" ``` -**Resource Visibility Flags** +##### Resource Visibility Flags By default, Pulse only shows resources with problems (unhealthy pods, failing deployments). To see all resources: @@ -241,8 +241,8 @@ roleRef: Talos Linux is immutable, so you cannot install the agent via the shell script. Use the DaemonSet approach above. ### Agent Configuration for Talos -* **Storage**: Talos mounts the ephemeral OS on `/`. Persistent data is usually in `/var`. The Pulse agent generally doesn't store state, but if it did, ensure it maps to a persistent path. -* **Network**: The agent will report the Pod IP by default. To report the Node IP, set `PULSE_REPORT_IP` using the Downward API: +- **Storage**: Talos mounts the ephemeral OS on `/`. Persistent data is usually in `/var`. The Pulse agent generally doesn't store state, but if it did, ensure it maps to a persistent path. +- **Network**: The agent will report the Pod IP by default. To report the Node IP, set `PULSE_REPORT_IP` using the Downward API: Add this to the DaemonSet `env` section: ```yaml @@ -254,6 +254,6 @@ Talos Linux is immutable, so you cannot install the agent via the shell script. ## 4. Troubleshooting -* **Agent not showing in UI**: Check logs for the DaemonSet pods, for example: `kubectl logs -l app=pulse-agent -n pulse`. -* **"Permission Denied" on metrics**: Ensure `securityContext.privileged: true` is set or proper capabilities are added. -* **Connection Refused**: Ensure `PULSE_URL` is correct and reachable from the agent pods. +- **Agent not showing in UI**: Check logs for the DaemonSet pods, for example: `kubectl logs -l app=pulse-agent -n pulse`. +- **"Permission Denied" on metrics**: Ensure `securityContext.privileged: true` is set or proper capabilities are added. +- **Connection Refused**: Ensure `PULSE_URL` is correct and reachable from the agent pods. diff --git a/docs/METRICS_HISTORY.md b/docs/METRICS_HISTORY.md index 6d2de4d07..78b29d0f9 100644 --- a/docs/METRICS_HISTORY.md +++ b/docs/METRICS_HISTORY.md @@ -58,8 +58,8 @@ These endpoints require authentication with the `monitoring:read` scope. `GET /api/metrics-store/history` supports: -- `resourceType` (required): `node`, `guest`, `storage`, `docker`, `dockerHost` -- `resourceId` (required): resource identifier +- `resourceType` (required): `node`, `vm`, `container`, `storage`, `dockerHost`, `dockerContainer` +- `resourceId` (required): resource identifier (for VMs/containers use `instance:node:vmid`) - `metric` (optional): `cpu`, `memory`, `disk`, etc. Omit to return all metrics for the resource. - `range` (optional): `1h`, `6h`, `12h`, `24h`, `7d`, `30d`, `90d` (default `24h`) @@ -67,7 +67,7 @@ Example: ```bash curl -H "X-API-Token: $TOKEN" \ - "http://localhost:7655/api/metrics-store/history?resourceType=guest&resourceId=vm-100&range=7d&metric=cpu" + "http://localhost:7655/api/metrics-store/history?resourceType=vm&resourceId=pve1:node1:100&range=7d&metric=cpu" ``` ## Troubleshooting diff --git a/docs/OIDC.md b/docs/OIDC.md index 0a0bc5118..29c2ced79 100644 --- a/docs/OIDC.md +++ b/docs/OIDC.md @@ -5,12 +5,12 @@ Enable Single Sign-On (SSO) with providers like Authentik, Keycloak, Okta, and A ## 🚀 Quick Start 1. **Configure Provider**: Create an OIDC application in your IdP. - * **Redirect URI**: `https:///api/oidc/callback` - * **Scopes**: `openid`, `profile`, `email` + - **Redirect URI**: `https:///api/oidc/callback` + - **Scopes**: `openid`, `profile`, `email` 2. **Enable in Pulse**: Go to **Settings → Security → Single Sign-On**. 3. **Enter Details**: - * **Issuer URL**: The base URL of your IdP (e.g., `https://auth.example.com/application/o/pulse/`). - * **Client ID & Secret**: From your IdP. + - **Issuer URL**: The base URL of your IdP (e.g., `https://auth.example.com/application/o/pulse/`). + - **Client ID & Secret**: From your IdP. 4. **Save**: The login page will now show a "Continue with Single Sign-On" button. > **Tip**: To hide the username/password form and only show the SSO button, set `PULSE_AUTH_HIDE_LOCAL_LOGIN=true` in your environment. You can still access the local login by appending `?show_local=true` to the URL (e.g., `https://your-pulse-instance/?show_local=true`). @@ -30,9 +30,9 @@ Enable Single Sign-On (SSO) with providers like Authentik, Keycloak, Okta, and A ### Access Control Restrict access to specific users or groups: -* **Allowed Groups**: Only users in these groups can login. Requires the `groups` scope/claim. -* **Allowed Domains**: Restrict to specific email domains (e.g., `example.com`). -* **Allowed Emails**: Allow specific email addresses. +- **Allowed Groups**: Only users in these groups can login. Requires the `groups` scope/claim. +- **Allowed Domains**: Restrict to specific email domains (e.g., `example.com`). +- **Allowed Emails**: Allow specific email addresses. ### Group-to-Role Mapping (Pro) @@ -86,21 +86,21 @@ For persistent sessions that don't require frequent re-authentication: ## 📚 Provider Examples ### Authentik -* **Type**: OAuth2/OpenID (Confidential) -* **Redirect URI**: `https://pulse.example.com/api/oidc/callback` -* **Signing Key**: Must use **RS256** (create a certificate/key pair if needed). -* **Issuer URL**: `https://auth.example.com/application/o/pulse/` +- **Type**: OAuth2/OpenID (Confidential) +- **Redirect URI**: `https://pulse.example.com/api/oidc/callback` +- **Signing Key**: Must use **RS256** (create a certificate/key pair if needed). +- **Issuer URL**: `https://auth.example.com/application/o/pulse/` ### Keycloak -* **Client ID**: `pulse` -* **Access Type**: Confidential -* **Valid Redirect URIs**: `https://pulse.example.com/api/oidc/callback` -* **Issuer URL**: `https://keycloak.example.com/realms/myrealm` +- **Client ID**: `pulse` +- **Access Type**: Confidential +- **Valid Redirect URIs**: `https://pulse.example.com/api/oidc/callback` +- **Issuer URL**: `https://keycloak.example.com/realms/myrealm` ### Azure AD -* **Redirect URI**: `https://pulse.example.com/api/oidc/callback` (Web) -* **Issuer URL**: `https://login.microsoftonline.com//v2.0` -* **Note**: Enable "ID tokens" in Authentication settings. +- **Redirect URI**: `https://pulse.example.com/api/oidc/callback` (Web) +- **Issuer URL**: `https://login.microsoftonline.com//v2.0` +- **Note**: Enable "ID tokens" in Authentication settings. ## 🔧 Troubleshooting diff --git a/docs/PROXY_AUTH.md b/docs/PROXY_AUTH.md index 6000be6e0..b7a22064d 100644 --- a/docs/PROXY_AUTH.md +++ b/docs/PROXY_AUTH.md @@ -19,7 +19,7 @@ Authenticate users via your existing reverse proxy (Authentik, Authelia, Cloudfl | `PROXY_AUTH_SECRET` | **Required**. Shared secret to verify requests. | - | | `PROXY_AUTH_USER_HEADER` | **Required**. Header containing the username. | - | | `PROXY_AUTH_ROLE_HEADER` | Header containing user groups/roles. | - | -| `PROXY_AUTH_ROLE_SEPARATOR` | Separator for multiple roles in the header. | `|` | +| `PROXY_AUTH_ROLE_SEPARATOR` | Separator for multiple roles in the header. | `\|` | | `PROXY_AUTH_ADMIN_ROLE` | Role name that grants admin access. | `admin` | | `PROXY_AUTH_LOGOUT_URL` | URL to redirect to after logout. | - | diff --git a/docs/PROXY_CONTROL_PLANE.md b/docs/PROXY_CONTROL_PLANE.md deleted file mode 100644 index 7ac54c5fb..000000000 --- a/docs/PROXY_CONTROL_PLANE.md +++ /dev/null @@ -1,43 +0,0 @@ -# 📡 Proxy Control Plane - -The Control Plane synchronizes `pulse-sensor-proxy` instances with the Pulse server, ensuring they trust the correct nodes without manual configuration. - -> **Deprecated in v5:** `pulse-sensor-proxy` (and its control-plane sync) is deprecated and not recommended for new deployments. New installs should use `pulse-agent --enable-proxmox` for temperature monitoring. - -> **Important**: The control-plane endpoints are disabled by default. Set `PULSE_ENABLE_SENSOR_PROXY=true` on the Pulse server to enable legacy proxy support. - -## 🏗️ Architecture - -```mermaid -graph LR - Pulse[Pulse Server] -- HTTPS /api/temperature-proxy --> Proxy[Sensor Proxy] - Proxy -- SSH --> Nodes[Cluster Nodes] -``` - -1. **Registration**: The proxy registers with Pulse on startup/install. -2. **Sync**: The proxy periodically fetches the "Authorized Nodes" list from Pulse. -3. **Validation**: The proxy only executes commands on nodes authorized by Pulse. - -## 🔄 Workflow - -1. **Install**: `install-sensor-proxy.sh` calls `/api/temperature-proxy/register`. -2. **Token Exchange**: Pulse returns a control-plane token which the proxy saves to `/etc/pulse-sensor-proxy/.pulse-control-token`. -3. **Polling**: The proxy polls `/api/temperature-proxy/authorized-nodes` every 60s (configurable). -4. **Update**: If the node list changes (e.g., a new node is added to Pulse), the proxy updates its internal allowlist automatically. - -## ⚙️ Configuration - -The proxy configuration in `/etc/pulse-sensor-proxy/config.yaml` handles the sync: - -```yaml -pulse_control_plane: - url: https://pulse.example.com:7655 - token_file: /etc/pulse-sensor-proxy/.pulse-control-token - refresh_interval: 60 -``` - -## 🛡️ Security - -* **Tokens**: The control-plane token is unique per proxy instance. -* **Least Privilege**: The proxy only knows about nodes explicitly added to Pulse. -* **Fallback**: If the control plane is unreachable, the proxy uses its last known good configuration. diff --git a/docs/README.md b/docs/README.md index 87a7ca1ba..44ac10cd2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -68,9 +68,6 @@ Pulse Pro unlocks **LLM-backed AI Patrol** — automated background monitoring t --- -
-

Found a bug or have a suggestion?

- - GitHub Issues - -
+Found a bug or have a suggestion? + +[![GitHub Issues](https://img.shields.io/badge/GitHub-Issues-green)](https://github.com/rcourtman/Pulse/issues) diff --git a/docs/RELEASE_NOTES.md b/docs/RELEASE_NOTES.md index 2e1449807..59dee0cdd 100644 --- a/docs/RELEASE_NOTES.md +++ b/docs/RELEASE_NOTES.md @@ -1,8 +1,7 @@ # Release Notes Pulse release notes live on GitHub: -https://github.com/rcourtman/Pulse/releases + For historical v4 notes that previously lived in this repo, see: `docs/releases/RELEASE_NOTES_v4.md` - diff --git a/docs/SECURITY_CHANGELOG.md b/docs/SECURITY_CHANGELOG.md index 0b9e4cf4a..432ce9338 100644 --- a/docs/SECURITY_CHANGELOG.md +++ b/docs/SECURITY_CHANGELOG.md @@ -54,7 +54,7 @@ allowed_nodes: # Require cluster membership validation strict_node_validation: true -``` +```text **Default Behavior:** If `allowed_nodes` is empty and proxy runs on Proxmox host, automatically validates against cluster membership (secure by default). @@ -241,7 +241,7 @@ allowed_peers: #### Enhanced Metrics New Prometheus metrics for security monitoring: -``` +```text pulse_proxy_node_validation_failures_total{reason} pulse_proxy_read_timeouts_total pulse_proxy_write_timeouts_total @@ -378,7 +378,7 @@ go build ./cmd/pulse-sensor-proxy ### References - **Temperature Monitoring Overview:** `docs/security/TEMPERATURE_MONITORING.md` -- **Sensor Proxy Hardening:** `docs/security/SENSOR_PROXY_HARDENING.md` +- **Sensor Proxy Hardening:** Standardized security controls for legacy deployments. --- @@ -396,4 +396,4 @@ All fixes implemented and tested 2025-11-07. --- -**For questions or security concerns, file issues at:** https://github.com/rcourtman/Pulse/issues +**For questions or security concerns, file issues at:** diff --git a/docs/TEMPERATURE_MONITORING.md b/docs/TEMPERATURE_MONITORING.md index 732b1e2ce..98d4c81dd 100644 --- a/docs/TEMPERATURE_MONITORING.md +++ b/docs/TEMPERATURE_MONITORING.md @@ -13,7 +13,7 @@ curl -fsSL http://:7655/install.sh | \ bash -s -- --url http://:7655 --token --enable-proxmox ``` -If you use the agent method, the rest of this document (sensor proxy) is optional. See `docs/security/TEMPERATURE_MONITORING.md` for the security model overview. +If you use the agent method, the rest of this document (sensor proxy) is optional. ## Migration: pulse-sensor-proxy → pulse-agent @@ -79,14 +79,14 @@ If running Pulse in Docker, you must install the proxy on the host and share the ```bash curl -fsSL https://github.com/rcourtman/Pulse/releases/latest/download/install-sensor-proxy.sh | \ sudo bash -s -- --standalone --pulse-server http://:7655 - ``` + ```text 2. **Update `docker-compose.yml`**: Add the socket volume to your Pulse service: ```yaml volumes: - /mnt/pulse-proxy:/run/pulse-sensor-proxy:ro - ``` + ```text > **Note**: The standalone installer creates the socket at `/mnt/pulse-proxy` on the host. Map it to `/run/pulse-sensor-proxy` inside the container. 3. **Restart Pulse**: `docker compose up -d` @@ -103,7 +103,7 @@ If you have Pulse running on **Server A** and want to monitor temperatures on ** Replace `` with the LXC container ID where Pulse runs on Server A (e.g., `100`). 2. The installer will detect that the container doesn't exist locally and install in **host monitoring only** mode: - ``` + ```text [WARN] Container 100 does not exist on this node [WARN] Will install sensor-proxy for host temperature monitoring only ``` @@ -137,15 +137,15 @@ journalctl -u pulse-sensor-proxy -f 1. **Pulse Sensor Proxy**: A lightweight service runs on the Proxmox host. 2. **Secure Access**: It reads sensors (via `lm-sensors`) and exposes them securely. 3. **Transport**: - * **Local**: Uses a Unix socket (`/run/pulse-sensor-proxy`) for zero-latency, secure access. - * **Remote**: Uses mutual TLS over HTTPS (port 8443). + - **Local**: Uses a Unix socket (`/run/pulse-sensor-proxy`) for zero-latency, secure access. + - **Remote**: Uses mutual TLS over HTTPS (port 8443). 4. **No SSH Keys**: Pulse containers no longer need SSH keys to read temperatures. --- ## 🔧 Advanced Configuration -#### Manual Configuration (No Script) +### Manual Configuration (No Script) If you can't run the installer script, create the configuration manually: @@ -375,8 +375,7 @@ ls -l /run/pulse-sensor-proxy/pulse-sensor-proxy.sock journalctl -u pulse-sensor-proxy -f ``` -Forward these logs off-host for retention by following -[operations/SENSOR_PROXY_LOGS.md](operations/SENSOR_PROXY_LOGS.md). +Forward these logs off-host for retention by following standard rsyslog/syslog practices. In the Pulse container, check the logs at startup: ```bash @@ -730,7 +729,6 @@ pulse-sensor-proxy config set-allowed-nodes --replace --merge 192.168.0.1 - Installer uses CLI (no more shell/Python divergence) **See also:** -- [Sensor Proxy Config Management Guide](operations/SENSOR_PROXY_CONFIG.md) - Complete runbook - [Sensor Proxy CLI Reference](../cmd/pulse-sensor-proxy/README.md) - Full command documentation ## Control-Plane Sync & Migration @@ -786,7 +784,7 @@ If temperature monitoring isn't working: ssh root@cluster-node "sensors -j" ``` -3. **Check GitHub Issues:** https://github.com/rcourtman/Pulse/issues +3. **Check GitHub Issues:** 4. **Include in bug report:** - Pulse version - Deployment type (LXC/Docker/native) diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index 833f5a091..80769667b 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -34,56 +34,56 @@ sudo pulse bootstrap-token ### Authentication -**"Invalid username or password" after setup** +#### "Invalid username or password" after setup - **Docker Compose**: Did you escape the `$` signs in your hash? Use `$$2a$$...`. - **Truncated Hash**: Ensure your bcrypt hash is exactly 60 characters. -**Cannot login / 401 Unauthorized** +#### Cannot login / 401 Unauthorized - Clear browser cookies. - Check if your IP is locked out (wait 15 mins). - If another admin can log in, use `POST /api/security/reset-lockout` to clear the lockout for your username or IP. -**Audit Log verification shows unsigned events** +#### Audit Log verification shows unsigned events - **Symptom**: Audit Log entries show “Unsigned” or verification fails in the UI. - **Root cause**: `PULSE_AUDIT_SIGNING_KEY` is not set, so events are stored without signatures. - **Fix**: Set `PULSE_AUDIT_SIGNING_KEY` and restart Pulse Pro. Newly created events will be signed; existing unsigned events remain unsigned. -**Audit Log is empty** +#### Audit Log is empty - **Symptom**: Audit Log shows zero events or "Console Logging Only." - **Root cause**: OSS build uses console logging only, or Pulse Pro audit logging is not enabled. - **Fix**: Use Pulse Pro with audit logging enabled, then generate new audit events (logins, token creation, password changes). -**Audit Log verification fails for older events** +#### Audit Log verification fails for older events - **Symptom**: Older events fail verification while newer events pass. - **Root cause**: The signing key changed or was rotated, so signatures no longer match. - **Fix**: Keep `PULSE_AUDIT_SIGNING_KEY` stable. If rotated intentionally, expect older events to fail verification. ### Monitoring Data -**VMs show "-" for disk usage** +#### VMs show "-" for disk usage - Install **QEMU Guest Agent** in the VM. - Enable "QEMU Guest Agent" in Proxmox VM Options. - Restart the VM. - See [VM Disk Monitoring](VM_DISK_MONITORING.md). -**Temperature data missing** +#### Temperature data missing - Install `lm-sensors` on the host. - Run `sensors-detect`. - Install the unified agent on the Proxmox host with `--enable-proxmox`. - See [Temperature Monitoring](TEMPERATURE_MONITORING.md). -**Docker hosts appearing/disappearing** +#### Docker hosts appearing/disappearing - **Duplicate IDs**: Cloned VMs often share `/etc/machine-id`. - **Fix**: Run `rm /etc/machine-id && systemd-machine-id-setup` on the clone. ### Notifications -**Emails not sending** +#### Emails not sending - Check SMTP settings in **Alerts → Notification Destinations**. - Check logs: `docker logs pulse | grep email`. - Ensure your SMTP provider allows the connection (e.g., Gmail App Passwords). -**Webhooks failing** +#### Webhooks failing - Verify the URL is reachable from the Pulse server. - If targeting private IPs, allow them in **Settings → System → Network → Webhook Security**. - Check Pulse logs for HTTP status codes and response bodies. diff --git a/docs/UNIFIED_AGENT.md b/docs/UNIFIED_AGENT.md index e4e4720b3..32d472150 100644 --- a/docs/UNIFIED_AGENT.md +++ b/docs/UNIFIED_AGENT.md @@ -85,7 +85,6 @@ curl -fsSL http://:7655/install.sh | \ Legacy env var: `PULSE_KUBE_INCLUDE_ALL_POD_FILES` is still accepted for backward compatibility. - ## Auto-Detection Auto-detection behavior: @@ -178,7 +177,6 @@ The agent can report S.M.A.R.T. disk temperatures when running in Agent mode. Th - **Disk exclusions** (`--disk-exclude` / `PULSE_DISK_EXCLUDE`) also apply to S.M.A.R.T. monitoring. Use patterns like `sda`, `/dev/sdb`, `nvme*`, or `*cache*` to exclude specific block devices. - ## Auto-Update The unified agent automatically checks for updates every hour. When a new version is available: diff --git a/docs/VM_DISK_MONITORING.md b/docs/VM_DISK_MONITORING.md index 3da0f4003..1c05a9cd1 100644 --- a/docs/VM_DISK_MONITORING.md +++ b/docs/VM_DISK_MONITORING.md @@ -17,9 +17,7 @@ Monitor actual disk usage inside your VMs using the QEMU Guest Agent. ## ⚙️ Requirements * **QEMU Guest Agent**: Must be installed and running inside the VM. -* **Proxmox Permissions**: - * **Proxmox 8**: `VM.Monitor` - * **Proxmox 9+**: `VM.GuestAgent.Audit` +* **Proxmox Permissions**: `VM.Monitor` (Proxmox 8) or `VM.GuestAgent.Audit` (Proxmox 9+). ## 🔧 Troubleshooting diff --git a/docs/api/SCHEDULER_HEALTH.md b/docs/api/SCHEDULER_HEALTH.md index ea23f81b6..28381da1c 100644 --- a/docs/api/SCHEDULER_HEALTH.md +++ b/docs/api/SCHEDULER_HEALTH.md @@ -85,20 +85,9 @@ Returns a real-time snapshot of the adaptive scheduler, including queue state, c ### Instances (`instances`) The authoritative source for per-instance health. -* **`pollStatus`**: - * `lastSuccess`: Timestamp of last successful poll. - * `lastError`: Details of the last error (message, category). - * `consecutiveFailures`: Current failure streak. -* **`breaker`**: - * `state`: `closed` (healthy), `open` (failing), `half_open` (recovering). - * `retryAt`: Next retry time if open/half-open. - * `since`: When the current breaker state started. - * `lastTransition`: Timestamp of the last state transition. -* **`deadLetter`**: - * `present`: `true` if the instance is in the DLQ (stopped polling). - * `reason`: Why it was moved to DLQ (e.g., `permanent_failure`). - * `retryCount`: DLQ retry attempts. - * `nextRetry`: Next scheduled retry (if any). +* **`pollStatus`**: `lastSuccess` timestamp, `lastError` details, `consecutiveFailures` count. +* **`breaker`**: `state` (`closed`/`open`/`half_open`), `retryAt` next retry, `since` state start, `lastTransition` timestamp. +* **`deadLetter`**: `present` flag, `reason` (e.g., `permanent_failure`), `retryCount`, `nextRetry` if scheduled. ### Top-Level Queue and DLQ * **`queue`**: Snapshot of the active task queue (depth + per-type counts). diff --git a/docs/monitoring/ADAPTIVE_POLLING.md b/docs/monitoring/ADAPTIVE_POLLING.md index 82d97d841..39c268ab0 100644 --- a/docs/monitoring/ADAPTIVE_POLLING.md +++ b/docs/monitoring/ADAPTIVE_POLLING.md @@ -3,12 +3,12 @@ Pulse uses an adaptive scheduler to optimize polling based on instance health and activity. ## 🧠 Architecture -* **Scheduler**: Calculates intervals based on health/staleness. -* **Priority Queue**: Min-heap keyed by `NextRun`. -* **Circuit Breaker**: Prevents hot loops on failing instances using success/failure counters. -* **Backoff**: Exponential retry delays (5s min to 5m max). -* **Worker Pool**: One worker per configured instance (PVE/PBS/PMG), capped at 10. -* **Global Concurrency Cap**: At most 2 polling cycles run at once to avoid resource spikes. +- **Scheduler**: Calculates intervals based on health/staleness. +- **Priority Queue**: Min-heap keyed by `NextRun`. +- **Circuit Breaker**: Prevents hot loops on failing instances using success/failure counters. +- **Backoff**: Exponential retry delays (5s min to 5m max). +- **Worker Pool**: One worker per configured instance (PVE/PBS/PMG), capped at 10. +- **Global Concurrency Cap**: At most 2 polling cycles run at once to avoid resource spikes. ## 🔬 Implementation Details (Developer Info) @@ -43,6 +43,7 @@ Adaptive polling is **disabled by default**. There is currently no dedicated UI for adaptive polling in v5. ### Environment Variables + | Variable | Default | Description | | :--- | :--- | :--- | | `ADAPTIVE_POLLING_ENABLED` | `false` | Enable/disable. | @@ -66,6 +67,7 @@ Exposed at `:9091/metrics`. | `pulse_scheduler_queue_due_soon` | Gauge | Tasks due in the next 12 seconds. | ## ⚡ Circuit Breaker + | State | Trigger | Recovery | | :--- | :--- | :--- | | **Closed** | Normal operation. | — | @@ -78,7 +80,7 @@ Exposed at `:9091/metrics`. `GET /api/monitoring/scheduler/health` (Auth required) Returns: -* Queue depth & breakdown. -* Dead-letter tasks. -* Circuit breaker states. -* Per-instance staleness. +- Queue depth & breakdown. +- Dead-letter tasks. +- Circuit breaker states. +- Per-instance staleness. diff --git a/docs/monitoring/PROMETHEUS_METRICS.md b/docs/monitoring/PROMETHEUS_METRICS.md index 0cc610554..4c53ebaf3 100644 --- a/docs/monitoring/PROMETHEUS_METRICS.md +++ b/docs/monitoring/PROMETHEUS_METRICS.md @@ -11,6 +11,7 @@ This listener is separate from the main UI/API port (`7655`). In Docker and Kube **Helm note:** the current chart exposes only port `7655`, so Prometheus scraping requires an additional Service that targets `9091` (and a matching ServiceMonitor). ## 🌐 HTTP Ingress + | Metric | Type | Description | | :--- | :--- | :--- | | `pulse_http_request_duration_seconds` | Histogram | Latency buckets by `method`, `route`, `status`. | @@ -18,6 +19,7 @@ This listener is separate from the main UI/API port (`7655`). In Docker and Kube | `pulse_http_request_errors_total` | Counter | Error totals by `method`, `route`, `status_class` (`client_error`, `server_error`, `none`). | ## 🔄 Polling & Nodes + | Metric | Type | Description | | :--- | :--- | :--- | | `pulse_monitor_poll_duration_seconds` | Histogram | Per-instance poll latency. | @@ -34,6 +36,7 @@ This listener is separate from the main UI/API port (`7655`). In Docker and Kube | `pulse_monitor_node_poll_staleness_seconds` | Gauge | Seconds since last node success (`-1` if never succeeded). | ## 🧠 Scheduler Health + | Metric | Type | Description | | :--- | :--- | :--- | | `pulse_scheduler_queue_due_soon` | Gauge | Tasks due within the next 12 seconds. | @@ -45,6 +48,7 @@ This listener is separate from the main UI/API port (`7655`). In Docker and Kube | `pulse_scheduler_breaker_retry_seconds` | Gauge | Seconds until next retry allowed. | ## ⚡ Diagnostics Cache + | Metric | Type | Description | | :--- | :--- | :--- | | `pulse_diagnostics_cache_hits_total` | Counter | Cache hits. | @@ -52,6 +56,7 @@ This listener is separate from the main UI/API port (`7655`). In Docker and Kube | `pulse_diagnostics_refresh_duration_seconds` | Histogram | Refresh latency. | ## 🚨 Alert Lifecycle + | Metric | Type | Description | | :--- | :--- | :--- | | `pulse_alerts_active` | Gauge | Active alerts by `level` and `type`. | @@ -63,6 +68,6 @@ This listener is separate from the main UI/API port (`7655`). In Docker and Kube | `pulse_alert_duration_seconds` | Histogram | Time from alert fire to resolve (by `type`). | ## 🚨 Alerting Examples -* **High Error Rate**: `rate(pulse_http_request_errors_total[5m]) > 0.05` -* **Stale Node**: `pulse_monitor_node_poll_staleness_seconds > 300` -* **Breaker Open**: `pulse_scheduler_breaker_state == 2` +- **High Error Rate**: `rate(pulse_http_request_errors_total[5m]) > 0.05` +- **Stale Node**: `pulse_monitor_node_poll_staleness_seconds > 300` +- **Breaker Open**: `pulse_scheduler_breaker_state == 2` diff --git a/docs/operations/ADAPTIVE_POLLING_ROLLOUT.md b/docs/operations/ADAPTIVE_POLLING_ROLLOUT.md index aa2c88ed2..3e85371f2 100644 --- a/docs/operations/ADAPTIVE_POLLING_ROLLOUT.md +++ b/docs/operations/ADAPTIVE_POLLING_ROLLOUT.md @@ -11,19 +11,19 @@ Safely enable dynamic scheduling (v5+). ## 🟢 Enable Choose one method: -* **UI**: Not currently exposed in the v5 UI (use CLI or env vars). -* **CLI**: - - systemd/LXC: `jq '.adaptivePollingEnabled=true' /etc/pulse/system.json > /tmp/system.json && sudo mv /tmp/system.json /etc/pulse/system.json` - - Docker/Kubernetes: edit `/data/system.json` in the volume and restart the container/pod -* **Env**: `ADAPTIVE_POLLING_ENABLED=true` (Docker/K8s). +- **UI**: Not currently exposed in the v5 UI (use CLI or env vars). +- **CLI**: + - systemd/LXC: `jq '.adaptivePollingEnabled=true' /etc/pulse/system.json > /tmp/system.json && sudo mv /tmp/system.json /etc/pulse/system.json` + - Docker/Kubernetes: edit `/data/system.json` in the volume and restart the container/pod +- **Env**: `ADAPTIVE_POLLING_ENABLED=true` (Docker/K8s). ## 🔍 Monitor (First 15m) Watch for stability: ```bash watch -n 5 'curl -s http://localhost:9091/metrics | grep pulse_monitor_poll_queue_depth' ``` -* **Success**: Queue depth < 50, no permanent errors. -* **Failure**: High queue depth, open breakers. +- **Success**: Queue depth < 50, no permanent errors. +- **Failure**: High queue depth, open breakers. ## ↩️ Rollback If instability occurs > 10m: diff --git a/docs/operations/AUDIT_LOG_ROTATION.md b/docs/operations/AUDIT_LOG_ROTATION.md deleted file mode 100644 index df82e23d6..000000000 --- a/docs/operations/AUDIT_LOG_ROTATION.md +++ /dev/null @@ -1,54 +0,0 @@ -# 🔄 Sensor Proxy Audit Log Rotation - -> **Deprecated in v5:** `pulse-sensor-proxy` is deprecated and not recommended for new deployments. -> This document is retained for existing installations during the migration window. - -The proxy writes append-only, hash-chained logs to `/var/log/pulse/sensor-proxy/audit.log`. - -## ⚠️ Important -* **Do not delete**: The file is protected with `chattr +a`. -* **Rotate when**: >200MB or >30 days. - -## 🛠️ Manual Rotation - -Run as root: - -```bash -# 1. Unlock file -chattr -a /var/log/pulse/sensor-proxy/audit.log - -# 2. Rotate (copy & truncate) -cp -a /var/log/pulse/sensor-proxy/audit.log /var/log/pulse/sensor-proxy/audit.log.$(date +%Y%m%d) -: > /var/log/pulse/sensor-proxy/audit.log - -# 3. Relock & Restart -chown pulse-sensor-proxy:pulse-sensor-proxy /var/log/pulse/sensor-proxy/audit.log -chmod 0640 /var/log/pulse/sensor-proxy/audit.log -chattr +a /var/log/pulse/sensor-proxy/audit.log -systemctl restart pulse-sensor-proxy -``` - -## 🤖 Logrotate Config - -Create `/etc/logrotate.d/pulse-sensor-proxy`: - -```conf -/var/log/pulse/sensor-proxy/audit.log { - weekly - rotate 8 - compress - missingok - notifempty - create 0640 pulse-sensor-proxy pulse-sensor-proxy - sharedscripts - prerotate - /usr/bin/chattr -a /var/log/pulse/sensor-proxy/audit.log || true - endscript - postrotate - /bin/systemctl restart pulse-sensor-proxy.service || true - /usr/bin/chattr +a /var/log/pulse/sensor-proxy/audit.log || true - endscript -} -``` - -**Note**: Do NOT use `copytruncate`. The restart is required to reset the hash chain. diff --git a/docs/operations/AUTO_UPDATE.md b/docs/operations/AUTO_UPDATE.md index f4b6fab5e..938ca81b2 100644 --- a/docs/operations/AUTO_UPDATE.md +++ b/docs/operations/AUTO_UPDATE.md @@ -4,6 +4,7 @@ Manage Pulse auto-updates on host-mode installations. > **Note**: Docker/Kubernetes users should manage updates via their orchestrator. ## ⚙️ Components + | File | Purpose | | :--- | :--- | | `pulse-update.timer` | Daily check (02:00 + jitter). | diff --git a/docs/operations/SENSOR_PROXY_CONFIG.md b/docs/operations/SENSOR_PROXY_CONFIG.md deleted file mode 100644 index 75aa41ffa..000000000 --- a/docs/operations/SENSOR_PROXY_CONFIG.md +++ /dev/null @@ -1,44 +0,0 @@ -# ⚙️ Sensor Proxy Configuration - -> **Deprecated in v5:** `pulse-sensor-proxy` is deprecated and not recommended for new deployments. -> Use `pulse-agent --enable-proxmox` for temperature monitoring. -> This document is retained for existing installations during the migration window. - -Safe configuration management using the built-in CLI. - -## 📂 Files -* **`config.yaml`**: General settings (logging, metrics). -* **`allowed_nodes.yaml`**: Authorized node list (managed via CLI). - -## 🛠️ CLI Reference - -### Validation -Check for errors before restart. -```bash -pulse-sensor-proxy config validate -``` - -### Managing Nodes -**Add Nodes (Merge):** -```bash -pulse-sensor-proxy config set-allowed-nodes --merge 192.168.0.10 -``` - -**Replace List:** -```bash -pulse-sensor-proxy config set-allowed-nodes --replace \ - --merge 192.168.0.1 --merge 192.168.0.2 -``` - -## ⚠️ Troubleshooting - -**Validation Fails:** -* Check for duplicate `allowed_nodes` blocks in `config.yaml`. -* Run `pulse-sensor-proxy config validate 2>&1` for details. - -**Lock Errors:** -* Remove stale locks if process is dead: `rm /etc/pulse-sensor-proxy/*.lock`. - -**Empty List:** -* Valid for IPC-only clusters. -* Populate manually if needed using `--replace`. diff --git a/docs/operations/SENSOR_PROXY_LOGS.md b/docs/operations/SENSOR_PROXY_LOGS.md deleted file mode 100644 index a1d1dc0a1..000000000 --- a/docs/operations/SENSOR_PROXY_LOGS.md +++ /dev/null @@ -1,35 +0,0 @@ -# 📝 Sensor Proxy Log Forwarding - -> **Deprecated in v5:** `pulse-sensor-proxy` is deprecated and not recommended for new deployments. -> Use `pulse-agent --enable-proxmox` for temperature monitoring. -> This document is retained for existing installations during the migration window. - -Forward `audit.log` and `proxy.log` to a central SIEM via RELP + TLS. - -## 🚀 Quick Start -Run the helper script with your collector details: - -```bash -sudo REMOTE_HOST=logs.example.com \ - REMOTE_PORT=6514 \ - CERT_DIR=/etc/pulse/log-forwarding \ - CA_CERT=/path/to/ca.crt \ - CLIENT_CERT=/path/to/client.crt \ - CLIENT_KEY=/path/to/client.key \ - bash -c "$(curl -fsSL https://raw.githubusercontent.com/rcourtman/Pulse/main/scripts/setup-log-forwarding.sh)" -``` - -## 📋 What It Does -1. **Inputs**: Watches `/var/log/pulse/sensor-proxy/{audit,proxy}.log`. -2. **Queue**: Disk-backed queue (50k messages) for reliability. -3. **Output**: RELP over TLS to `REMOTE_HOST`. -4. **Mirror**: Local debug file at `/var/log/pulse/sensor-proxy/forwarding.log`. - -## ✅ Verification -1. **Check Status**: `sudo systemctl status rsyslog` -2. **View Mirror**: `tail -f /var/log/pulse/sensor-proxy/forwarding.log` -3. **Test**: Restart proxy and check remote collector for `pulse.audit` tag. - -## 🧹 Maintenance -* **Disable**: Remove `/etc/rsyslog.d/pulse-sensor-proxy.conf` and restart rsyslog. -* **Rotate Certs**: Replace files in `CERT_DIR` and restart rsyslog. diff --git a/docs/releases/RELEASE_NOTES_v4.md b/docs/releases/RELEASE_NOTES_v4.md index 010afa362..eb9e71be8 100644 --- a/docs/releases/RELEASE_NOTES_v4.md +++ b/docs/releases/RELEASE_NOTES_v4.md @@ -3,29 +3,29 @@ This file archives the v4-era release notes that previously lived at `docs/RELEASE_NOTES.md`. For current releases, refer to GitHub Releases: -https://github.com/rcourtman/Pulse/releases + --- -# Pulse v4.31.0 +## Pulse v4.31.0 -## What's Changed +### What's Changed (v4.31.0) -### Temperature monitoring over HTTPS +#### Temperature monitoring over HTTPS - `pulse-sensor-proxy` now exposes an authenticated HTTPS endpoint per Proxmox host. Pulse stores each proxy’s URL + bearer token and always polls `https://node:8443/temps` before falling back to local sockets or SSH, eliminating the fragile “single proxy for every node” chain. - Installations auto-register via the new `/api/temperature-proxy/register` endpoint, generate 4096-bit certificates, enforce CIDR allowlists, and log every HTTP request through the proxy’s audit pipeline. - The backend temperature collector understands proxy URLs/tokens, respects strict timeouts, and publishes richer diagnostics so operators can see which node failed and why. -### Installer, diagnostics, and UI updates +#### Installer, diagnostics, and UI updates - `scripts/install-sensor-proxy.sh` gained `--http-mode` / `--http-addr`, automatic TLS generation, rollback-on-failure, allowed subnet auto-population, and a comprehensive uninstall path that purges sockets, TLS secrets, and LXC bind mounts. - A new `Settings → Diagnostics → Temperature Proxy` table surfaces proxy health, registration status, and the errors returned by the HTTPS endpoint. - `scripts/tests/test-sensor-proxy-http.sh` exercises the HTTP installer path end-to-end inside Docker to prevent regressions. -### Host agent refinements +#### Host agent refinements - Windows PowerShell installers/uninstallers now log verbosely, harden permissions, and clean up services more reliably. - Linux host-agent scripts aligned with the new diagnostics UX and scoped token workflow so onboarding is less error-prone. -## Upgrade Notes +### Upgrade Notes (v4.31.0) Temperature monitoring will not work for remote nodes until every Proxmox host is reinstalled with the new HTTPS workflow. Follow these steps per host: @@ -46,7 +46,7 @@ curl -vk https://node.example:8443/health \ -H "Authorization: Bearer $(sudo cat /etc/pulse-sensor-proxy/.http-auth-token)" ``` -## Installation +### Installation (v4.31.0) - **Install or upgrade with the helper script** ```bash curl -sL https://github.com/rcourtman/Pulse/releases/latest/download/install.sh | bash @@ -72,7 +72,7 @@ curl -vk https://node.example:8443/health \ --namespace pulse --create-namespace ``` -## Downloads +### Downloads (v4.31.0) - Multi-arch Linux tarballs (amd64/arm64/armv7) - Standalone sensor proxy binaries (now include HTTP mode) - Helm chart archive (pulse-4.31.0-helm.tgz) @@ -81,29 +81,29 @@ curl -vk https://node.example:8443/health \ --- -# Pulse v4.26.1 +## Pulse v4.26.1 -## What's Changed -### New +### What's Changed (v4.26.1) +#### New - Standalone host agents now ship with guided Linux, macOS, and Windows installers that stream registration status back to Pulse, generate scoped commands from **Settings → Agents**, and feed host metrics into alerts alongside Proxmox and Docker. - Alert thresholds gained host-level overrides, connectivity toggles, and snapshot size guardrails so you can tune offline behaviour per host while keeping a global policy for other resources. - API tokens now support fine-grained scopes with a redesigned manager that previews command templates, highlights unused credentials, and makes revocation a single click. - Proxmox replication jobs surface in a dedicated **Proxmox → Replication** view with API plumbing to track task health and bubble failures into the monitoring pipeline. - Docker Swarm environments now receive service/task-aware reporting with configurable scope, plus a Docker settings view that highlights manager/worker roles, stack health, rollout status, and service alert thresholds. -### Improvements +#### Improvements - Dashboard loads and drawer links respond faster thanks to cached guest metadata, reduced polling allocations, and inline URL editing that no longer flashes on WebSocket updates. - Settings navigation is reorganized with dedicated platform and agent sections, richer filters, and platform icons that make onboarding and discovery workflows clearer. - LXC guests now report dynamic interface IPs, configuration metadata, and queue metrics so alerting, discovery, and drawers stay accurate even during rapid container churn. - Notifications consolidate into a consistent toast system, with clearer feedback during agent setup, token generation, and background job state changes. -### Bug Fixes +#### Bug Fixes - Enforced explicit node naming and respected custom Proxmox ports so cluster discovery, overrides, and disk monitoring defaults remain intact after edits. - Hardened setup-token flows and checksum handling in the installers to prevent stale credentials and guarantee the correct binaries are fetched. - Treated 501 responses from the Proxmox API as non-fatal during failover, restored FreeBSD disk counter parsing, and stopped guest link icons from re-triggering animations on updates. - Preserved inline editor state across WebSocket refreshes and ensured Docker host identifiers stay collision-safe in mixed environments. -## Installation +### Installation (v4.26.1) - **Install or upgrade with the helper script** ```bash curl -sL https://github.com/rcourtman/Pulse/releases/latest/download/install.sh | bash @@ -129,7 +129,7 @@ curl -vk https://node.example:8443/health \ --namespace pulse --create-namespace ``` -## Downloads +### Downloads (v4.26.1) - Multi-arch Linux tarballs (amd64/arm64/armv7) - Standalone sensor proxy binaries - Helm chart archive (pulse-4.26.1-helm.tgz) diff --git a/docs/security/SENSOR_PROXY_APPARMOR.md b/docs/security/SENSOR_PROXY_APPARMOR.md deleted file mode 100644 index d3df7fe7a..000000000 --- a/docs/security/SENSOR_PROXY_APPARMOR.md +++ /dev/null @@ -1,47 +0,0 @@ -# 🛡️ Sensor Proxy AppArmor (Optional) - -> **Deprecated in v5:** `pulse-sensor-proxy` is deprecated and not recommended for new deployments. -> Use `pulse-agent --enable-proxmox` for temperature monitoring. -> This document is retained for existing installations during the migration window. - -Secure `pulse-sensor-proxy` with AppArmor and Seccomp. - -## 🛡️ AppArmor - -Profile: `security/apparmor/pulse-sensor-proxy.apparmor` -* **Allows**: Configs, logs, SSH keys, outbound TCP/SSH. -* **Blocks**: Raw sockets, module loading, ptrace, exec outside allowlist. - -### Install & Enforce -```bash -curl -fsSL https://raw.githubusercontent.com/rcourtman/Pulse/main/security/apparmor/pulse-sensor-proxy.apparmor | \ - sudo tee /etc/apparmor.d/pulse-sensor-proxy >/dev/null -sudo apparmor_parser -r /etc/apparmor.d/pulse-sensor-proxy -sudo aa-enforce pulse-sensor-proxy -``` - -## 🔒 Seccomp - -Profile: `security/seccomp/pulse-sensor-proxy.json` -* **Allows**: Go runtime syscalls, network, file IO. -* **Blocks**: Everything else (returns `EPERM`). - -### Systemd (Classic) -Add to service override: -```ini -[Service] -AppArmorProfile=pulse-sensor-proxy -SystemCallFilter=@system-service -SystemCallAllow=accept;connect;recvfrom;sendto;recvmsg;sendmsg;sendmmsg;getsockname;getpeername;getsockopt;setsockopt;shutdown -``` - -### Containers (Docker/Podman) -```bash -curl -fsSL https://raw.githubusercontent.com/rcourtman/Pulse/main/security/seccomp/pulse-sensor-proxy.json | \ - sudo tee /etc/pulse-sensor-proxy.seccomp.json >/dev/null - -podman run --seccomp-profile /etc/pulse-sensor-proxy.seccomp.json ... -``` - -## 🔍 Verification -Check status with `aa-status` or `journalctl -t auditbeat`. diff --git a/docs/security/SENSOR_PROXY_HARDENING.md b/docs/security/SENSOR_PROXY_HARDENING.md deleted file mode 100644 index 607429b1b..000000000 --- a/docs/security/SENSOR_PROXY_HARDENING.md +++ /dev/null @@ -1,64 +0,0 @@ -# 🛡️ Sensor Proxy Hardening - -> **Deprecated in v5:** `pulse-sensor-proxy` is deprecated and not recommended for new deployments. -> Use `pulse-agent --enable-proxmox` for temperature monitoring. -> This document is retained for existing installations during the migration window. - -The `pulse-sensor-proxy` runs on the host to securely collect temperatures, keeping SSH keys out of containers. - -## 🏗️ Architecture -* **Host**: Runs `pulse-sensor-proxy` (unprivileged user). -* **Container**: Connects via Unix socket (`/run/pulse-sensor-proxy/pulse-sensor-proxy.sock`). -* **Auth**: Uses `SO_PEERCRED` to verify container UID/PID. - -## 🔒 Host Hardening - -### Service Account -Runs as `pulse-sensor-proxy` (no shell, no home). -```bash -id pulse-sensor-proxy # uid=XXX(pulse-sensor-proxy) -``` - -### Systemd Security -The service unit uses: -* `User=pulse-sensor-proxy` -* `NoNewPrivileges=true` -* `ProtectSystem=strict` -* `PrivateTmp=true` - -### File Permissions -| Path | Owner | Mode | -| :--- | :--- | :--- | -| `/var/lib/pulse-sensor-proxy/` | `pulse-sensor-proxy` | `0750` | -| `/var/lib/pulse-sensor-proxy/ssh/` | `pulse-sensor-proxy` | `0700` | -| `/run/pulse-sensor-proxy/` | `pulse-sensor-proxy` | `0775` | - -## 📦 LXC Configuration -Required for the container to access the proxy socket. - -**`/etc/pve/lxc/.conf`**: -```ini -unprivileged: 1 -lxc.apparmor.profile: generated -lxc.mount.entry: /run/pulse-sensor-proxy mnt/pulse-proxy none bind,create=dir 0 0 -``` - -## 🔑 Key Management -SSH keys are restricted to `sensors -j` only. - -**Rotation**: -```bash -bash -c "$(curl -fsSL https://raw.githubusercontent.com/rcourtman/Pulse/main/scripts/pulse-proxy-rotate-keys.sh)" -``` -* **Dry Run**: Add `--dry-run`. -* **Rollback**: Add `--rollback`. - -## 🚨 Incident Response -If compromised: -1. **Stop Proxy**: `systemctl stop pulse-sensor-proxy`. -2. **Rotate Keys**: Remove old keys from nodes manually or use the rotation helper above. -3. **Audit Logs**: Check `journalctl -u pulse-sensor-proxy`. -4. **Reinstall**: - ```bash - curl -fsSL https://github.com/rcourtman/Pulse/releases/latest/download/install-sensor-proxy.sh | sudo bash - ``` diff --git a/docs/security/SENSOR_PROXY_NETWORK.md b/docs/security/SENSOR_PROXY_NETWORK.md deleted file mode 100644 index a3d185109..000000000 --- a/docs/security/SENSOR_PROXY_NETWORK.md +++ /dev/null @@ -1,39 +0,0 @@ -# 🌐 Sensor Proxy Network Segmentation - -> **Deprecated in v5:** `pulse-sensor-proxy` is deprecated and not recommended for new deployments. -> Use `pulse-agent --enable-proxmox` for temperature monitoring. -> This document is retained for existing installations during the migration window. - -Isolate the proxy to prevent lateral movement. - -## 🚧 Zones -* **Pulse App**: Connects to Proxy via Unix socket (local). -* **Sensor Proxy**: Outbound SSH to Proxmox nodes only. -* **Proxmox Nodes**: Accept SSH from Proxy. -* **Logging**: Accepts RELP/TLS from Proxy. - -## 🛡️ Firewall Rules - -| Source | Dest | Port | Purpose | Action | -| :--- | :--- | :--- | :--- | :--- | -| **Pulse App** | Proxy | `unix` | RPC Requests | **Allow** (Local) | -| **Proxy** | Nodes | `22` | SSH (sensors) | **Allow** | -| **Proxy** | Logs | `6514` | Audit Logs | **Allow** | -| **Any** | Proxy | `22` | SSH Access | **Deny** (Use Bastion) | -| **Proxy** | Internet | `any` | Outbound | **Deny** | - -## 🔧 Implementation (iptables) -```bash -# Allow SSH to Proxmox -iptables -A OUTPUT -p tcp -d --dport 22 -j ACCEPT - -# Allow Log Forwarding -iptables -A OUTPUT -p tcp -d --dport 6514 -j ACCEPT - -# Drop all other outbound -iptables -P OUTPUT DROP -``` - -## 🚨 Monitoring -* Alert on outbound connections to non-whitelisted IPs. -* Monitor `pulse_proxy_limiter_rejects_total` for abuse. diff --git a/docs/security/TEMPERATURE_MONITORING.md b/docs/security/TEMPERATURE_MONITORING.md index ea83644cb..0f210b2ba 100644 --- a/docs/security/TEMPERATURE_MONITORING.md +++ b/docs/security/TEMPERATURE_MONITORING.md @@ -32,9 +32,9 @@ The agent runs `sensors -j` locally and reports temperatures directly to Pulse. `pulse-sensor-proxy` is deprecated in v5 and is not recommended for new deployments. This section is retained for existing installations during the migration window. ### 🛡️ Security Model -* **Isolation**: SSH keys live on the host, not in the container. -* **Least Privilege**: Proxy runs as `pulse-sensor-proxy` (no shell). -* **Verification**: Container identity verified via `SO_PEERCRED`. +- **Isolation**: SSH keys live on the host, not in the container. +- **Least Privilege**: Proxy runs as `pulse-sensor-proxy` (no shell). +- **Verification**: Container identity verified via `SO_PEERCRED`. ### 🏗️ Components 1. **Pulse Backend**: Connects to Unix socket `/mnt/pulse-proxy/pulse-sensor-proxy.sock`. @@ -43,14 +43,14 @@ The agent runs `sensors -j` locally and reports temperatures directly to Pulse. ### 🔒 Key Restrictions SSH keys deployed to nodes are locked down: -``` +```text command="sensors -j",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ``` ### 🚦 Rate Limiting -* **Per Peer**: ~12 req/min. -* **Concurrency**: Max 2 parallel requests per peer. -* **Global**: Max 8 concurrent requests. +- **Per Peer**: ~12 req/min. +- **Concurrency**: Max 2 parallel requests per peer. +- **Global**: Max 8 concurrent requests. ### 📝 Auditing All requests logged to system journal: @@ -61,6 +61,5 @@ Logs include: `uid`, `pid`, `method`, `node`, `correlation_id`. ### Related Docs -- Sensor proxy hardening: `docs/security/SENSOR_PROXY_HARDENING.md` -- Network segmentation: `docs/security/SENSOR_PROXY_NETWORK.md` -- AppArmor/Seccomp: `docs/security/SENSOR_PROXY_APPARMOR.md` +- Unified Agent Security: [`docs/AGENT_SECURITY.md`](../AGENT_SECURITY.md) +- Repository Security Policy: [`/SECURITY.md`](../../SECURITY.md) diff --git a/internal/api/DO_NOT_EDIT_FRONTEND_HERE.md b/internal/api/DO_NOT_EDIT_FRONTEND_HERE.md index 13b163422..25b1bfa29 100644 --- a/internal/api/DO_NOT_EDIT_FRONTEND_HERE.md +++ b/internal/api/DO_NOT_EDIT_FRONTEND_HERE.md @@ -2,7 +2,7 @@ This `frontend-modern` directory is **AUTO-GENERATED** during builds. -## The REAL frontend location is: +## The REAL frontend location is ### `/opt/pulse/frontend-modern` ## Why does this exist? @@ -14,10 +14,10 @@ This `frontend-modern` directory is **AUTO-GENERATED** during builds. - **YOUR CHANGES WILL BE LOST** on the next build - The Makefile deletes and recreates this directory -## How to edit frontend code: +## How to edit frontend code 1. Edit files in `/opt/pulse/frontend-modern/src/` 2. The dev server (port 7655) will hot-reload 3. When building for production, the Makefile copies it here --- -This file exists to prevent confusion. The directory structure is intentional and required by Go's limitations. \ No newline at end of file +This file exists to prevent confusion. The directory structure is intentional and required by Go's limitations. diff --git a/internal/api/README.md b/internal/api/README.md index 147356494..596ec3c10 100644 --- a/internal/api/README.md +++ b/internal/api/README.md @@ -19,4 +19,4 @@ Go's `//go:embed` directive has limitations: 2. Cannot follow symbolic links 3. Must embed files within the Go module -This is a known Go limitation and our structure works around it. \ No newline at end of file +This is a known Go limitation and our structure works around it. diff --git a/tests/integration/QUICK_START.md b/tests/integration/QUICK_START.md index 0e1e1d82d..b63ff3b24 100644 --- a/tests/integration/QUICK_START.md +++ b/tests/integration/QUICK_START.md @@ -13,7 +13,7 @@ This guide will help you get the update integration tests running quickly. ```bash cd tests/integration ./scripts/setup.sh -``` +```text This will: - Install npm dependencies @@ -85,11 +85,11 @@ npm run docker:rebuild While the test environment is running: -- **Pulse UI**: http://localhost:7655 -- **Mock GitHub API**: http://localhost:8080 +- **Pulse UI**: +- **Mock GitHub API**: - **Health checks**: - - http://localhost:7655/api/health - - http://localhost:8080/health + - + - ## Viewing Test Results @@ -175,7 +175,7 @@ See `.github/workflows/test-updates.yml` for CI configuration. ## Architecture -``` +```text ┌─────────────────┐ ┌──────────────────┐ ┌─────────────────────┐ │ Playwright │────▶│ Pulse Server │────▶│ Mock GitHub API │ │ (Browser UI) │ │ (Test Instance) │ │ (Controlled │ @@ -216,4 +216,4 @@ test('my new test', async ({ page }) => { - Check the [main README](./README.md) for detailed information - Review existing test files for examples - Check Docker logs for service issues -- Review Playwright documentation: https://playwright.dev +- Review Playwright documentation: diff --git a/tests/integration/README.md b/tests/integration/README.md index 76a35ebc3..70d4d0385 100644 --- a/tests/integration/README.md +++ b/tests/integration/README.md @@ -4,7 +4,7 @@ End-to-end Playwright tests that validate critical user flows against a running ## Architecture -``` +```text ┌─────────────────┐ ┌──────────────────┐ ┌─────────────────────┐ │ Playwright │────▶│ Pulse Server │────▶│ Mock GitHub API │ │ (Browser UI) │ │ (Test Instance) │ │ (Controlled │