Repository navigation
Releases
v0.1.5
Includes every change from 0.1.4, which was tagged but not published: its image failed the release's vulnerability
scan.
Security
github.com/go-jose/go-jose/v4is updated to v4.1.6 for CVE-2026-116587 (denial of service when parsing JWKs that
contain RSA keys).pulsedparses the JWKS of configured single sign-on providers with it, so a hostile or
compromised provider could cause a denial of service.
Fixed (from 0.1.4)
- The System page and a client's page show each connection's round-trip time in milliseconds, like the NATS card,
instead of the raw NATS value (1.371958msnext to910µs). - An event's size is the same everywhere: subject, headers and payload, as in the Explorer list and the rollups. The
event detail (GET /api/admin/v1/events/{stream}/{seq}) and the live tail (dashboard andGET /api/v1/tail)
counted only the subject and payload. - Connection snippets for a new client or HTTP token show only what its grants allow. A client without a subscribe
grant no longer gets a subscribe example onevt.example.>, a client with only a durable grant gets a durable
subscription, and a token gets only the publish, replay and tail examples its grants allow. - The Audit page shows the whole actor (it was cut off at about 20 characters, such as
user:alex@example.c); long
values are truncated with the full text on hover.
Container image for linux/amd64 and linux/arm64 (same digest in both registries):
docker.io/aurimasniekis/pulsed:0.1.5(docker.io/aurimasniekis/pulsed@sha256:0f540b01a1660ac3a1ef1b2933932ffeda97b8523f4fe41a8eaec22c9e9855cb)ghcr.io/aurimasniekis/pulsed:0.1.5(ghcr.io/aurimasniekis/pulsed@sha256:0f540b01a1660ac3a1ef1b2933932ffeda97b8523f4fe41a8eaec22c9e9855cb)
Verify: gh attestation verify oci://ghcr.io/aurimasniekis/pulsed:0.1.5 --repo aurimasniekis/go-pulse.
v0.1.3
Added
- Personal access tokens can name source networks. With the new
PULSE_ADMIN_PUBLIC_TOKENS=true(off by default; needs
PULSE_ADMIN_PUBLIC), such a token also works on the public dashboard host, but only from those networks, so
automation like Terraform in CI can reach the admin API without an SSH tunnel. Set networks on the Account page or
withpulsed admin token --cidr; each must be at least /16 (IPv4) or /48 (IPv6). Tokens without networks stay
loopback-only, and refused tokens on the public host count towards a ban.
Security
- Opting in with
PULSE_ADMIN_PUBLIC_TOKENSrelaxes the earlier rule that personal access tokens work only on the
loopback listener. A token with networks can be used by anyone who can send traffic from those networks; keep them
narrow and prefer the operator role for automation.
Container image for linux/amd64 and linux/arm64 (same digest in both registries):
docker.io/aurimasniekis/pulsed:0.1.3(docker.io/aurimasniekis/pulsed@sha256:2ca63b849fcf95873b49489b794d7f4f34a8c80ba14ef462f1af82da67da8d3e)ghcr.io/aurimasniekis/pulsed:0.1.3(ghcr.io/aurimasniekis/pulsed@sha256:2ca63b849fcf95873b49489b794d7f4f34a8c80ba14ef462f1af82da67da8d3e)
Verify: gh attestation verify oci://ghcr.io/aurimasniekis/pulsed:0.1.3 --repo aurimasniekis/go-pulse.
v0.1.2
Fixed
- The disk forecast no longer fires for a new or quiet stream. When the stream would take more than about 292 years to
fill, the date overflowed to one in the past, so the alert reported "-106752.0 days" and the Overview showed a date
in 1734. Forecasts beyond 100 years now have no date, like a stream with no traffic. - The documented nftables edge rule (operator firewall guide and bans page) now matches only traffic addressed to the
host (fib daddr type local). The old rule also dropped the containers' own outbound HTTPS, which broke ACME
certificates, the Cloudflare ban-list sync and the Cloudflare range refresh.
Container image for linux/amd64 and linux/arm64 (same digest in both registries):
docker.io/aurimasniekis/pulsed:0.1.2(docker.io/aurimasniekis/pulsed@sha256:d43beeeda255d3fc1836f77fc7357300de1fadb2d40051e80478c5034f77a738)ghcr.io/aurimasniekis/pulsed:0.1.2(ghcr.io/aurimasniekis/pulsed@sha256:d43beeeda255d3fc1836f77fc7357300de1fadb2d40051e80478c5034f77a738)
Verify: gh attestation verify oci://ghcr.io/aurimasniekis/pulsed:0.1.2 --repo aurimasniekis/go-pulse.
v0.1.1
Added
- The single sign-on groups claim can name a nested claim with a dotted path, such as
porch.groupsfor Porch. A
top-level claim with exactly that name still takes precedence, so names likehttps://example.com/groupskeep
working.
Container image for linux/amd64 and linux/arm64 (same digest in both registries):
docker.io/aurimasniekis/pulsed:0.1.1(docker.io/aurimasniekis/pulsed@sha256:e797f6a51ecb62d5b8d469b819188348a6f6a7986dd1dfca8edccd6f8f29d470)ghcr.io/aurimasniekis/pulsed:0.1.1(ghcr.io/aurimasniekis/pulsed@sha256:e797f6a51ecb62d5b8d469b819188348a6f6a7986dd1dfca8edccd6f8f29d470)
Verify: gh attestation verify oci://ghcr.io/aurimasniekis/pulsed:0.1.1 --repo aurimasniekis/go-pulse.
v0.1.0
First release. Pulse is a personal durable event bus on NATS JetStream: tools publish and subscribe with their own
least-privilege credentials, any tool can replay history from a timestamp, and one server with a dashboard manages
clients, webhooks, bans, alerts and backups. The image is docker.io/aurimasniekis/pulsed:0.1.0 (also
ghcr.io/aurimasniekis/pulsed:0.1.0) for linux/amd64 and linux/arm64.
Not externally reviewed. Nobody other than the author has reviewed the code, the key handling or the backup
format.
Known limitations
- Pre-1.0: interfaces may change between minor versions (docs/VERSIONING.md).
- The reference deployment (firewall, ban enforcement, IPv6 client addresses, host roles) was tested in containers,
including a Debian 13 converge test, but not yet on a real VPS behind Cloudflare. - The memory budget for the 2 vCPU / 2 GB target and the subject-cardinality guideline are provisional: the sizing
spike (about 10 GB of events, 5,000 subjects) has not been run. - Webhook verifiers are tested against documented vectors, not live GitHub or Stripe deliveries; single sign-on is
tested against an in-process identity provider, not a live one such as Keycloak or Entra ID. - A
subscribegrant can pull from another client's consumer on the same stream if it knows the consumer's name. EVENTScannot be shrunk from Pulse: a lowerPULSE_EVENTS_MAX_BYTESis ignored with a warning.- No visual regression tests for the dashboard; browser tests run in Chromium only.
Added
pulsed version|healthcheck; embedded dashboard shell (Mantine 8, TanStack Router); distroless image; CI and release
workflows.pulsed init(sealed key store, operator modenats.conf, bootstrap TLS, banagent token),pulsed serve
(SQLite state, SYS/APP connections, APP account sync), client identities with per-client scoped signing keys,
pulsed keys export, dev compose stack, reference prod compose.- Envelope package and SDK conformance vectors,
EVENTSandblobsensured at start, Go SDK (pkg/pulse),
pulse context|pub|sub, sizing spike tooling (make spike, operator-triggered). - Admin API (system, streams, consumers, explorer, SSE tail) and public listener skeleton on Huma v2, Host
allowlist and CSRF header on the admin listener,pulsed openapi, generated TypeScript client types. - Dashboard Explorer, Live tail and Streams & consumers pages, NATS status in the header, Playwright smoke tests.
- Rollups (minute/hour/day counts by prefix and type, exactly once), subject index, disk forecast; Overview and
Subjects pages; admin publish endpoint and "Publish event" in the Explorer. - HTTP tokens and the public ingress API (publish, batch, request bridge, replay, SSE tail); client, token and
audit admin APIs; Clients, HTTP tokens and Audit pages with show-once secrets and connection snippets. - Inbound webhooks (GitHub, Stripe, HMAC, shared secret) and outbound webhooks (ordered, retried, signed,
SSRF-guarded) with a delivery log; Webhooks page. - Automatic bans (NATS, HTTP, webhooks) enforced over HTTP, in nftables (
pulsed banagent) and optionally in a
Cloudflare IP list; origin TLS with hot reload and Authenticated Origin Pulls; Cloudflare-aware client IP;/ws
proxy; Security page. Prod now requiresPULSE_AOP_CA_FILEfor the public listener. - Let's Encrypt for raw NATS (
PULSE_ACME_*): DNS-01 via Cloudflare, served next to the internal leaf by SNI,
verified after reload, renewed early;GET /system/certificates; System page with server, NATS, JetStream and
certificate status;make test-acme(pebble). - Prometheus
/metrics(pulsed, NATS, JetStream, streams, Go runtime); alert engine with built-in and custom
threshold rules,_sys.alert.<rule>events and history; Telegram and Discord notifiers (PULSE_TELEGRAM_*,
PULSE_DISCORD_*); Alerts page; System page with runtime, server stats and connections; Grafana Alloy in the dev
stack and a reference config. - Nightly age-encrypted backups to S3 (
PULSE_BACKUP_*): SQLite,keys.encand every stream as NATSARC1
snapshots stored deduplicated; verification, GFS retention, authenticated restores from the Backups page and
pulsed backup keygen|list|run|restore; SeaweedFS in the dev stack. - KV & Objects browser, Settings page (effective configuration, display time zone), audit time filters, and a
Playwright check of every page. - Python SDK (
sdk/python) and TypeScript SDK (@pulse/sdk, node and browser over/ws) with conformance and
Go ↔ Python ↔ TS interop tests. pulseCLI:tail,req, andstreams,clients ls|create|rotate|revoke,backup ls|run|restorethrough the
admin API tunnel. Operator guides indocs/operator/(deployment, keys, TLS, bans, backups, upgrades,
troubleshooting).- Apache-2.0 license, a README,
SECURITY.mdandCONTRIBUTING.md, and a documentation website built from
site/(VitePress) and deployed to GitHub Pages, with screenshots from a throwaway stack (make screenshots). - Dashboard users and single sign-on: local accounts with Argon2id passwords,
mandatory TOTP for administrators and operators, recovery codes, invitations and password links; administrator,
operator, auditor and viewer roles with a permission on every admin operation; server-side sessions with CSRF tokens
and re-authentication for sensitive actions; OpenID Connect providers (PKCE, group → role mappings, just-in-time
users, linking, test logins, SSO-only, step-up); personal access tokens for the CLI;pulsed admin bootstrap|recover|token;
the dashboard optionally on the public listener on its own or the API hostname (PULSE_ADMIN_PUBLIC,
PULSE_ADMIN_PUBLIC_HOST,PULSE_ADMIN_URL);PULSE_SESSION_IDLE,PULSE_SESSION_MAX,PULSE_REAUTH_WINDOW,
PULSE_MFA_REQUIRED_ROLES;pulse_dashboard_logins_total;make dev-admin. - Admin API endpoints for declarative tooling such as the
Terraform provider:DELETE /clients/{id}and
DELETE /tokens/{id}remove revoked (or, for tokens, expired) records so their names can be reused, keeping client
revocations in force;GET|PUT /streams/{name}/consumers/{consumer}reads and creates or updates a durable pull
consumer;GET|PUT /kv/{bucket}/configandGET|PUT /objects/{bucket}/configread and update a bucket's
description, history, TTL and size limit. Consumers reportack_wait_seconds,max_deliver,max_ack_pending
and the start position; KV buckets reportdescriptionandmax_bytes, object storesmax_bytes.
Security
- No anonymous dashboard access: every admin operation is authorized by role; failed dashboard sign-ins are
throttled, audited and, on the public listener, count toward bans (dashboardsource). - Outbound webhook delivery errors never include the destination URL, which can carry a secret.
Container image for linux/amd64 and linux/arm64 (same digest in both registries):
docker.io/aurimasniekis/pulsed:0.1.0(docker.io/aurimasniekis/pulsed@sha256:7a9d0afbd24c13aa606653bd4fb2513daeae10b6e04812b45a224fb742206500)ghcr.io/aurimasniekis/pulsed:0.1.0(ghcr.io/aurimasniekis/pulsed@sha256:7a9d0afbd24c13aa606653bd4fb2513daeae10b6e04812b45a224fb742206500)
Verify: gh attestation verify oci://ghcr.io/aurimasniekis/pulsed:0.1.0 --repo aurimasniekis/go-pulse.