# πŸ”₯ Flare Ephemeral, zero-dependency script telemetry for real-world automation. Run one Python file, open the dashboard URL it prints, source one wrapper line into a script, and watch that script report back in real time. Flare is built for short-lived operational work: - deployments - provisioning - migrations - maintenance windows - demos and labs - one-off admin scripts It is intentionally **not** a long-term logging stack. There is no database, no accounts, no agents, and no setup beyond `python3 flare.py`. --- ## What Flare Is Flare gives scripts and small automation jobs a disposable telemetry dashboard. Instead of hoping a job is still alive, your script can emit structured updates like: - starting - installing packages - waiting for service - completed - failed Those updates appear live in the browser, grouped by host. > **Flare is a disposable telemetry dashboard.** --- ## Why It Exists Most observability tooling is too heavy for quick operational work. If all you want is a live view into a script, standing up a whole logging or monitoring platform is overkill. Flare id the opposite: - **fast to start** - **easy to discard** --- ## Quick Start ```bash python3 flare.py ``` That is all you need. On startup, Flare prints: - a ready-to-open dashboard URL - wrapper import lines for bash / bash+python / PowerShell - exportable environment variables if you want to post manually - the exact per-run GET and POST capability URLs baked into this launch Open the dashboard URL in a browser, then paste one of the printed wrapper lines into a script. --- ## Basic Workflow 1. Start Flare 2. Open the dashboard URL from the startup banner 3. Source one wrapper into your script 4. Call helper functions like `mon`, `mon_detail`, `mon_complete`, or `mon_error` 5. Watch events arrive live in the browser 6. Export JSON or CSV if you want to keep the record All runtime data lives in memory only. --- ## Project Layout ```text flare/ β”œβ”€β”€ flare.py # server, wrappers, in-memory pub/sub └── flare.html # browser dashboard ``` `flare.py` uses only the Python standard library. --- ## Wrapper Options Pick whichever wrapper fits the target environment. | Wrapper | Command shape | Requirements | |---|---|---| | `wrapper.sh` | `eval "$( curl -s )"` | bash, python3 | | `wrapper.bash` | `eval "$( curl -s )"` | bash 4+, curl, openssl | | `wrapper.ps1` | `iex (irm )` | PowerShell 5.1+ or pwsh 7+ | All wrappers bake in the current run’s: - event destination URL - session/topic identifier - bearer token - HMAC secret, unless disabled Your script only needs to call helper functions. ```bash mon "message" mon_complete "message" mon_error "message" mon_detail "message" '{"key":"value"}' ``` - `mon` β€” normal running/progress update - `mon_complete` β€” successful completion - `mon_error` β€” failure / error state - `mon_detail` β€” progress update with structured JSON detail Example: ```bash mon "starting backup" mon_detail "installing packages" '{"packages":["nginx","fail2ban"]}' mon_complete "backup finished" ``` --- ## Summary Channel There is one reserved `mon_detail` title with special dashboard behavior: ```bash mon_detail "flare-summary" '{"site":"phx-1","phase":"patching","owner":"shane"}' ``` Events sent with title `flare-summary` are treated as summary metadata for that host. They populate the main detail area instead of appearing as a normal log entry. That is useful for: - current phase - change ticket / runbook identifiers - target version - site / cluster / environment - host-specific notes you want pinned in view --- ## Example: Bash Script ```bash #!/usr/bin/env bash set -euo pipefail # Use the exact printed wrapper URL from flare.py eval "$( curl -sf http://SERVER:8080/REPLACE_WITH_PRINTED_GET_PATH/wrapper.bash )" || { echo "flare unavailable, stubbing functions" >&2 mon() { echo "[flare] $1" >&2; } mon_complete() { mon "$1"; } mon_error() { mon "$1"; } mon_detail() { mon "$1"; } } mon_detail "flare-summary" '{"role":"db","change":"CHG-1234"}' mon "starting server hardening" mon_detail "system update" '{"action":"apt-get upgrade"}' apt-get update -qq apt-get upgrade -y -qq mon "configuring firewall" ufw default deny incoming ufw default allow outgoing ufw allow 22/tcp ufw --force enable mon_complete "hardening finished" ``` --- ## Example: Cloud-Init / First Boot ```yaml #cloud-config runcmd: - | eval "$( curl -sf http://SERVER:8080/REPLACE_WITH_PRINTED_GET_PATH/wrapper.bash )" mon_detail "flare-summary" '{"phase":"first boot","source":"cloud-init"}' mon "cloud-init starting on $(hostname)" apt-get update -qq && apt-get upgrade -y -qq mon "packages updated" mon_complete "$(hostname) ready" ``` Use the exact printed wrapper URL in real usage. --- ## Example: PowerShell ```powershell # Use the exact wrapper URL printed by flare.py iex (irm http://SERVER:8080/REPLACE_WITH_PRINTED_GET_PATH/wrapper.ps1) mon_detail "flare-summary" '{"phase":"patching","window":"nightly"}' mon "starting updates" mon_detail "patching" '{"phase":"download"}' mon_complete "updates complete" ``` --- ## Security Model Flare is still lightweight, but it is more deliberate than a naive callback endpoint. ### 1. Per-run session values Each launch generates fresh values unless you provide your own: - bearer token - HMAC secret - topic/session identifier - randomized browser-facing GET base path - randomized POST ingest path ### 2. Randomized GET base path Browser-facing resources live under a per-run random path, for example: ```text // //flare.html //wrapper.sh //wrapper.bash //wrapper.ps1 //events?topic=... ``` That makes sessions harder to casually enumerate and keeps one run’s browser-facing resources scoped to that run. ### 3. Randomized POST path Event ingest lives at a separate per-run path, for example: ```text / ``` That separates β€œcan view” from β€œcan submit.” Knowing the dashboard URL does not automatically reveal the POST target. ### 4. Bearer auth Event streaming and publish operations are tied to a token. ### 5. HMAC-signed event envelopes Wrappers sign their event content before sending it. The server validates those signatures before accepting events, and the dashboard can also surface verification status for received events. That means Flare is not just trusting any JSON that happens to hit the endpoint with the right shape. --- ## Why the Paths Exist Flare uses capability-style per-run URLs. In plain English: - the dashboard should not live at a predictable public root - wrappers should be scoped to the current run - event streaming should belong to the same run-specific namespace - message ingest should be isolated from browser-facing resources That is why the startup banner prints the **exact dashboard URL**, **exact wrapper URLs**, and **exact POST target** for that run. You are not meant to memorize or handcraft these paths. Just copy what Flare prints. --- ## Dashboard Features The dashboard is intentionally lightweight and host-oriented. Current behavior includes: - real-time SSE event streaming - host-tab grouping of activity - running / complete / error visibility - structured detail rendering - reserved `flare-summary` metadata area - JSON export - CSV export - direct open from the startup banner URL - client-side session behavior with no database backend The dashboard URL is preconfigured with the session values it needs for that one run. --- ## CLI Options ```text python3 flare.py [OPTIONS] --host HOST Bind address (default: 0.0.0.0) --port PORT Port (default: 8080) --token TOKEN Bearer token (generated if omitted) --secret SECRET HMAC secret (generated if omitted) --topic TOPIC Session/topic name (generated if omitted) --html PATH Path to flare.html (auto-detected if omitted) --get-path PATH Browser-facing GET base path (generated if omitted) --post-path PATH POST ingest path (generated if omitted) --no-secret Disable HMAC signing --verbose Debug / validation logging ``` ### Notes - `--topic` still exists internally, but the dashboard is host-oriented in practice. - `--get-path` lets you pin the browser-facing path if you do not want a generated one. - `--post-path` lets you pin the ingest path for controlled testing. - `--verbose` is useful when testing signatures and request behavior. --- ## Endpoints Flare’s stable shape is: | Method | Path | Auth | Purpose | |---|---|---|---| | GET | `//` | No | Dashboard | | GET | `//flare.html` | No | Dashboard file | | GET | `//wrapper.sh` | No | Bash + Python wrapper | | GET | `//wrapper.bash` | No | Pure Bash wrapper | | GET | `//wrapper.ps1` | No | PowerShell wrapper | | GET | `//events?topic=...&auth=...&since=all` | Token | SSE event stream | | POST | `/` | Token | Publish signed or unsigned event envelope | In normal usage, you should not need to hit these by hand. The startup banner and wrappers handle it for you. --- ## Tests Two test helpers are included in this repo layout: - `http_test.py` β€” direct HTTP tests for weird paths, params, headers, methods, auth, SSE, and POST validation - `src_test.py` β€” source the real wrappers, then exercise `mon`, `mon_detail`, `mon_complete`, and `mon_error` Both use one environment variable: ```bash export __FLARE_SRC='http://SERVER:8080/PRINTED_GET_PATH/wrapper.sh' ``` Then run: ```bash python3 http_test.py bash src_test.py ``` `http_test.py` derives the dashboard, wrapper, SSE, and POST targets from the wrapper exports. `src_test.py` exercises both `wrapper.sh` and `wrapper.bash` from that same seed URL. --- ## Architecture ```text β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” source wrapper β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Remote Host β”‚ ◄──────────────────────── β”‚ flare.py β”‚ β”‚ or Script β”‚ β”‚ server β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ mon() β”‚ ───── signed POST ──────► β”‚ in-memory β”‚ β”‚ mon_detail() β”‚ β”‚ storage β”‚ β”‚ mon_error() β”‚ β”‚ + SSE β”‚ β”‚ mon_complete() β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ SSE β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ flare.html β”‚ β”‚ dashboard β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` Everything is intentionally ephemeral. If you need to keep the output, export JSON or CSV from the dashboard before shutting it down. --- ## Tips ### Graceful fallback If Flare is unavailable, stub the functions and let the script continue. ### Use the printed URLs Because the GET and POST paths are generated per run, copying the banner output is the safest workflow. ### Export before exit Flare does not persist anything. If the session matters, export it before shutting the server down. --- ## License Do whatever you want with it.