Commit Graph
100 Commits
Author SHA1 Message Date
bvandeusenandClaude Opus 4.8 712aec60c1 test(host_agent): assert parsed agent version matches AGENT_VERSION constant
CI / lint (push) Successful in 2s
CI / unit (push) Successful in 7s
CI / integration (push) Successful in 2m11s
The on-disk-version test hardcoded '1.0.0' and broke on the 1.1.0 bump. Compare
against agent.AGENT_VERSION so future bumps don't require touching the test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 12:14:53 -04:00
bvandeusenandClaude Opus 4.8 3b2146bc7a feat(host_agent): agent reports its primary IP; mirror into Host.address (task 274)
CI / lint (push) Successful in 3s
CI / unit (push) Failing after 8s
CI / integration (push) Successful in 2m9s
The agent now detects its own primary non-loopback IP (UDP-socket trick, no
packets sent) and sends it in the metadata bag; bumps AGENT_VERSION 1.0.0->1.1.0
and re-detects on SIGHUP. The server persists it on HostAgentRegistration.host_ip
and mirrors it into Host.address ONLY when that field is blank — an admin-typed
address is never overwritten. The reported IP shows in the settings table so
admins can see drift regardless.

- agent.py: detect_primary_ip(); host_ip in collect_metadata(); refresh on reload
- routes.py: pure pick_host_address() helper; ingest persists host_ip + mirrors
- models.py + migration host_agent_002_host_ip: new String(45) column
- settings_list.html: Reported IP column
- plugin.yaml: 1.0.0 -> 1.1.0
- tests: pick_host_address (fill-when-blank / never-clobber / no-op),
  detect_primary_ip (never raises, non-loopback), metadata carries host_ip

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 12:11:41 -04:00
bvandeusenandClaude Opus 4.8 af60ca446d fix(plugins): complete steward rename across bundled plugins; clear lint debt
CI / integration (push) Successful in 2m8s
CI / lint (push) Successful in 3s
CI / unit (push) Successful in 7s
The fabledscryer->steward rename had only ever reached host_agent. The other
five bundled plugins (http, snmp, traefik, unifi, docker) still imported
`from fabledscryer.*` (package no longer exists) and read FABLEDSCRYER_* env
vars — so every one of them was broken at import since the original rebrand.
CI stayed green only because none are enabled by default and migrations don't
import plugin modules. Now that they version in-tree, complete the rename:
- fabledscryer.* -> steward.* imports across all five plugins
- FABLEDSCRYER_* -> STEWARD_* in plugin migration env.py files
- author/repository/homepage + user-facing 'Fabled Scryer' strings -> Steward
- snmp/scheduler.py: also drop dead `now`/datetime; record_metric from steward

Adds tests/test_no_legacy_names.py — fails if 'scryer'/'roundtable' ever
reappear in shipped code (the drift bit twice; this stops a third time).

Also clears pre-existing ruff lint debt (unused imports, semicolon statements,
mid-file import) surfaced by the new lint lane.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 11:22:20 -04:00
bvandeusenandClaude Opus 4.8 d925709c77 ci: add Forgejo CI (lint + unit + Postgres integration) + ci-requirements.md
CI / lint (push) Failing after 2s
CI / unit (push) Successful in 7s
CI / integration (push) Successful in 2m8s
Single-repo CI now that plugins are bundled in-tree. Three lanes on push to
dev/main, modeled on FabledCurator's canonical ci.yml (minus frontend/Redis):
- lint: ruff check steward/ plugins/ tests/ (no dep install)
- unit: pytest -m 'not integration' — whole current suite (testing=True mocks DB)
- integration: postgres:16-alpine service via socket-discovered bridge IP; a
  boot-and-migrate test creates the real app, running core + all bundled-plugin
  migrations, then round-trips the DB — guards the folded-in migration graph.

Registers the 'integration' pytest marker; adds tests/integration/test_boot.py.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 08:37:32 -04:00
bvandeusenandClaude Opus 4.8 a7a281cb11 feat(plugins): fold first-party plugins in-tree; bundled + external roots
First-party plugins (host_agent, http, snmp, traefik, unifi, docker) are now
tracked under plugins/ and baked into the image, so they version atomically
with core — ending the cross-repo import drift the roundtable->steward rename
exposed. History for these files is preserved in the archived Roundtable-plugins
repo.

Plugin discovery becomes multi-root: PLUGIN_DIR (single) -> PLUGIN_DIRS
(bundled first, then external) + PLUGIN_INSTALL_DIR. Bundled ships in the image;
third-party plugins still mount at runtime into the external root
(STEWARD_PLUGIN_DIR, default /data/plugins) and downloads/installs land there.
Bundled shadows external on a name collision.

- config.py: load_bootstrap returns plugin_dirs + plugin_install_dir
- app.py: iterate PLUGIN_DIRS at the migration + load sites
- migration_runner.py: discover_all_in() unions every plugin root
- plugin_manager.py: resolve_plugin_path() (pure, first-root-wins); load /
  install / hot-reload span all roots; installs target the external root
- settings/routes.py: _discover_plugins scans all roots, dedup bundled-first
- Dockerfile: COPY plugins/ ; docker-compose: drop host bind, document external
- tests/test_plugin_dirs.py: resolution, multi-root discovery, bootstrap split

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 08:37:24 -04:00
bvandeusenandClaude Opus 4.7 88ab5b917e chore: rename project Roundtable → Steward
Renames the Python package directory, CLI command, env var prefix,
docker-compose service/container/image, Postgres role/db, and all
visible branding. Marketing form is "Fabled Steward".

Clean break from the previous rebrand: drops the fabledscryer→roundtable
import shim in __init__.py and the FABLEDSCRYER_* env var fallback in
config.py and migrations/env.py. Env vars are now STEWARD_* only.

Heads-up for existing deployments:
- Postgres user/db renamed fabledscryer → steward in docker-compose.yml.
  Existing volumes need the role/db renamed inside Postgres, or override
  POSTGRES_USER/POSTGRES_DB to keep the old names.
- Host-agent systemd unit is now steward-agent.service. Existing agents
  keep running under the old name; reinstall to switch.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 16:20:14 -04:00
bvandeusen e118543b2e feat(dashboard): use public_base_url helper for share link generation 2026-04-16 00:18:45 -04:00
bvandeusen b7293588be feat(settings): public_base_url field in general settings UI 2026-04-15 20:30:12 -04:00
bvandeusen 5bc8ef2566 feat(settings): add public_base_url helper with request.host_url fallback 2026-04-15 20:29:49 -04:00
bvandeusen 3a3d094a2a test(settings): failing tests for public_base_url helper 2026-04-15 20:29:28 -04:00
bvandeusen 2c68ba5094 feat(settings): cache PUBLIC_BASE_URL into app.config on reload 2026-04-15 20:29:13 -04:00
bvandeusen fdbcc58385 feat(settings): add general.public_base_url default 2026-04-15 20:29:02 -04:00
bvandeusen dbe50794d3 Merge pull request 'feat: host_agent plugin — push-model host resource monitoring' (#1) from feat/host-agent into main 2026-04-15 13:43:57 +00:00
bvandeusenandClaude Opus 4.6 44cc2f2fce docs(plugins): catalog entry for host_agent
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 00:31:27 -04:00
bvandeusenandClaude Sonnet 4.6 3382bd956b test(host_agent): stale-agent filter (pure function)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 00:30:42 -04:00
bvandeusenandClaude Sonnet 4.6 f7e21c0a21 feat(host_agent): register widgets and alert metric catalog entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 22:31:31 -04:00
bvandeusenandClaude Sonnet 4.6 ded768c089 test(host_agent): install.sh template render + agent.py source parse
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 22:29:15 -04:00
bvandeusenandClaude Sonnet 4.6 5e0bfcc2b0 test(host_agent): pure-function tests for metric expansion
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 22:27:08 -04:00
bvandeusenandClaude Sonnet 4.6 673ba72510 test(host_agent): agent POST, backoff, and main loop
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 22:22:45 -04:00
bvandeusenandClaude Sonnet 4.6 8bed58073b test(host_agent): ring buffer and payload builder unit tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 22:09:12 -04:00
bvandeusenandClaude Sonnet 4.6 b6b1c8adca test(host_agent): agent resource collectors unit tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 22:07:39 -04:00
bvandeusenandClaude Sonnet 4.6 6056bad01e test(host_agent): agent config parser unit tests
Add read_config/ConfigError unit tests covering flat key-value parsing,
blank lines/comments, list fields, defaults, missing required keys, and
malformed lines. Also add tests/__init__.py to fix pytest namespace
collision with tests/plugins/ shadowing the root plugins/ package.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 21:44:46 -04:00
bvandeusenandClaude Opus 4.6 b1cfc377da docs(plugins): host_agent plan — path 1 note (no DB tests)
Records the mid-execution pivot: test harness uses testing=True which
mocks the DB, so plugin tests stick to pure-Python unit tests (agent +
metric expander). Server routes are verified manually.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 18:13:41 -04:00
bvandeusenandClaude Opus 4.6 98003f3458 docs(plugins): host_agent implementation plan
15-task TDD plan covering plugin scaffolding, agent collectors, ingest
route, install script, settings UI, widgets, detail page, scheduler,
and integration test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 23:46:37 -04:00
bvandeusenandClaude Opus 4.6 e243e0e0e1 docs(plugins): host-agent plugin design spec
Design for a push-based Python agent that collects CPU/memory/storage/
load/uptime from remote Linux hosts and POSTs to a new host_agent
plugin. Uses per-host bearer tokens, systemd install via curl|sh,
in-memory ring buffer with exponential backoff, and writes to the
existing PluginMetric bus plus a plugin-private registrations table.

No core schema changes — plugin stays strictly isolated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 23:35:12 -04:00
bvandeusenandClaude Opus 4.6 d6e094bbb5 refactor: remove broken NUT/UPS plugin and managed-NUT startup
The UPS plugin's default driver was snmp-ups, so NUT was just translating
network SNMP back into its own protocol — no value over polling the UPS
directly through the existing snmp plugin. The managed-NUT entrypoint path
also broke container startup when config was incomplete.

Deletes nut_setup.py, the NUT block from entrypoint.sh, NUT packages from
the Dockerfile, the ups entry from the plugin catalog example, and the
ups wiring in alerts METRIC_CATALOG, widgets, settings routes, and the
rules form. The plugins/ups source tree (untracked) is also removed from
the working copy. Existing ups_* DB tables are orphaned but harmless in
dev; a drop migration isn't needed.

Follow-up: rebuild "on battery → Ansible shutdown" automation on top of
the alerts system as a new action type that runs a playbook.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 22:41:08 -04:00
bvandeusen 0596f1d9c1 docs: roundtable rename sweep
Sweeps README, docs/, example configs, code docstrings, report and
notification subject lines, plugin catalog URL default, and stray
comments in Dockerfile/entrypoint.sh/.gitignore. Adds a legacy note
to docs/core/configuration.md explaining the FABLEDSCRYER_* fallback.
docker-compose DB credentials intentionally left as fabledscryer to
preserve the existing pgdata volume.
2026-04-13 20:16:25 -04:00
bvandeusen 55a4fac3e9 copy: flip visible wordmark → Roundtable
Updates nav brand, page <title> blocks across all templates, and the
read-only share view footer. Removes duplicate Roundtable heading from
login card now that the nav wordmark reads correctly.
2026-04-13 18:40:30 -04:00
bvandeusen 62d28b1032 build: docker-compose service → roundtable
Service, container_name, image, and env var name flipped to roundtable.
DB credentials kept as fabledscryer to preserve the existing pgdata
volume — a separate migration can rename the role/db later if desired.
2026-04-13 18:40:26 -04:00
bvandeusen ee0b22bafd chore(compose): mount docker socket and traefik log path
Enables the docker plugin to scrape container state and the traefik
access_log plugin to read host log files.
2026-04-13 18:06:05 -04:00
bvandeusen a64f2195de feat: ROUNDTABLE_* env vars with FABLEDSCRYER_* fallback
Reads ROUNDTABLE_<NAME> first, falls back to FABLEDSCRYER_<NAME> so
existing deployments keep working through the rebrand transition.
Covers DATABASE_URL, DATABASE__URL, SECRET_KEY, PLUGIN_DIR, CONFIG.
2026-04-13 17:40:16 -04:00
bvandeusenandClaude Opus 4.6 fcd26346a2 build: container paths point at roundtable package
Keeps the image buildable after the package rename. Image name, container
name, compose service, and env vars still flip in PR 4.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 17:29:47 -04:00
bvandeusenandClaude Opus 4.6 fad1c12eac feat: fabledscryer→roundtable import alias shim
Meta path finder redirects fabledscryer[.*] imports to roundtable[.*],
keeping unmodified plugin repos working during the rebrand transition.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 17:26:30 -04:00
bvandeusenandClaude Opus 4.6 1ecc831673 build: point alembic at roundtable/migrations
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 17:14:14 -04:00
bvandeusenandClaude Opus 4.6 2df0d421c2 build: rename package to roundtable in pyproject
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 17:14:07 -04:00
bvandeusenandClaude Opus 4.6 94a35da86e refactor: update imports fabledscryer → roundtable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 17:13:55 -04:00
bvandeusenandClaude Opus 4.6 8aad2ab43d refactor: rename package directory fabledscryer → roundtable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 17:10:31 -04:00
bvandeusenandClaude Opus 4.6 fd9c6d941d style(login): placeholder labels instead of field headers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 16:39:06 -04:00
bvandeusenandClaude Opus 4.6 ce43a3900b style(login): larger wordmark + tagline, drop Sign In heading
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 16:37:35 -04:00
bvandeusenandClaude Opus 4.6 c6401d8416 feat(login): Roundtable wordmark above tagline
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 16:13:36 -04:00
bvandeusenandClaude Opus 4.6 6c883e4121 copy: relocate "Under Watch, Under Care" to login tagline
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 15:45:05 -04:00
bvandeusenandClaude Opus 4.6 4d154653ba copy: dashboard hero "Under Watch, Under Care"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:58:38 -04:00
bvandeusenandClaude Opus 4.6 b0d9e9b6ad feat: themed 404 and 500 pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:57:45 -04:00
bvandeusenandClaude Opus 4.6 b6954bd9d2 copy: broader themed empty states + restore DNS CTA
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:56:41 -04:00
bvandeusenandClaude Opus 4.6 5a701e0558 copy: themed empty states + login tagline
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:55:10 -04:00
bvandeusenandClaude Opus 4.6 ba2c698801 style: candlelit glow background replaces star field
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:52:27 -04:00
bvandeusenandClaude Opus 4.6 e83c69c6c2 feat: heraldic seal logo (crown & ellipse table)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:51:47 -04:00
bvandeusenandClaude Opus 4.6 33df0c2f9a style: swap Libertinus Serif → EB Garamond
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:51:19 -04:00
bvandeusenandClaude Opus 4.6 e8691bc7e4 style: pewter & gold palette tokens
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:51:12 -04:00
bvandeusenandClaude Opus 4.6 1f6404f0fd docs: rebrand implementation plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:40:26 -04:00
bvandeusenandClaude Opus 4.6 39074252d1 docs: rebrand design spec (FabledScryer → Roundtable)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 14:30:40 -04:00
bvandeusenandClaude Sonnet 4.6 00dc4cdc9c feat: per-plugin settings pages and multi-repo plugin catalog
Plugin settings UI:
- Settings → Plugins now shows a clean list (status dot, name, enabled badge)
  with a Settings button per plugin linking to its own detail page
- Per-plugin detail page at /settings/plugins/<name>/ shows enable toggle,
  all config fields, load status, and failure notice if the plugin errored
- Config saving now scoped per-plugin via POST /settings/plugins/<name>/;
  removes the monolithic save-all-plugins form

Plugin repositories:
- Replace single Plugin Index URL field with a managed list of repositories
  (HTMX add/edit/remove per entry, same pattern as Ansible sources)
- plugin_index.py: fetch_catalog() now accepts a list of URLs, caches per-URL,
  and merges results deduplicating by plugin name (first repo wins)
- Legacy plugins.index_url is auto-migrated to the new list format on first
  access so existing installs don't lose their configured URL

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 18:41:31 -04:00
bvandeusenandClaude Sonnet 4.6 8558d15eeb feat: plugin fault isolation notices + NUT managed mode fixes
Plugin failures:
- Track load-time failures in _FAILED_PLUGINS dict with human-readable reasons
- Inject plugin_failures into all templates via context processor
- Show admin-only warning banner in base.html when any plugin fails to load
- Show inline failure notice per plugin card in Settings → Plugins

NUT managed mode:
- entrypoint.sh: make nut_setup.py failure non-fatal so the container starts
  even if nut_ups_host isn't set yet (allows fixing config via UI)
- save_plugins: when nut_managed is enabled, auto-set nut_host=localhost so
  the plugin connects to the managed NUT instance without extra manual config

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 18:04:53 -04:00
bvandeusenandClaude Sonnet 4.6 56283df5a1 feat: Ansible source manager UI — replace raw JSON textarea
- Replace the raw JSON textarea in Settings → Ansible with a proper
  per-source card UI: add, inline-edit, remove, and git-sync each
  source independently via HTMX without a page reload
- Each source card shows type badge (git/local), URL or path, branch,
  and pull interval; git sources get a Sync button that triggers
  git pull and returns inline status
- Add source form uses a type-aware select that shows URL/branch/interval
  fields for git or path field for local, collapsed in a details accordion
- Add new settings routes: sources/add, sources/<idx>/remove,
  sources/<idx>/save, sources/<idx>/sync
- Update browse.html and run_detail.html to use CSS vars throughout
  (removed hardcoded hex colors); link empty state to Settings page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 17:24:35 -04:00
bvandeusenandClaude Sonnet 4.6 edc9b752d2 feat: drag-and-drop dashboard editing, alert dynamic fields
- Replace up/down arrow reorder buttons on dashboard edit page with
  SortableJS drag handles; add POST /d/<id>/edit/reorder endpoint
  accepting ordered widget ID array
- Add {% block extra_scripts %} hook to base.html for page-specific JS
- Add dynamic alert rule field loading via HTMX partial (_rule_fields)
  so metric/threshold fields update when source is changed
- Add docs/plugins/index.yaml.example showing catalog index format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 08:16:04 -04:00
bvandeusenandClaude Sonnet 4.6 93d5ed8fb0 feat: managed NUT setup, plugin config improvements, migration fix
- Add managed NUT mode: configure NUT daemon from Settings → Plugins
  (UPS plugin), writes /data/nut_managed.json read by entrypoint on
  restart — no env vars or USB passthrough required
- entrypoint.sh: start NUT from /data/nut_managed.json or NUT_MANAGED=1
  env var; drop to app user via gosu after NUT daemons start
- nut_setup.py: support --from-file <json> in addition to env vars
- Dockerfile: add nut, nut-client, gosu packages and entrypoint
- docker-compose.yml: document optional NUT_MANAGED env var block
- Fix plugin hot-reload migration failure: pass all plugin migration
  dirs to Alembic so previously-stamped revisions from other plugins
  remain resolvable (fixes UPS and any plugin with depends_on)
- Fix plugin list-type config (e.g. SNMP devices) rendering as broken
  text input — now shows a read-only note to edit plugin.yaml instead
- Fix _sync_nut_managed_config: only write JSON when nut_ups_host is
  non-empty, preventing NUT startup loop on container restart

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 08:15:48 -04:00
bvandeusenandClaude Sonnet 4.6 ced1eebe1d feat: maintenance windows, reports, uptime widget, alert improvements
- Add maintenance window scheduling to suppress alerts during planned
  downtime (model, routes, templates)
- Add weekly email/webhook reports with host summary (core/reports.py,
  Settings → Reports tab)
- Add host uptime history widget with per-check sparkline view
- Expand alert rules: dynamic metric catalog for plugin sources,
  per-rule HTMX field loading, maintenance window awareness
- Register additional dashboard widgets (uptime, SNMP, UniFi, UPS)
- Add Settings → Reports tab configuration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 08:15:30 -04:00
bvandeusenandClaude Sonnet 4.6 3c70ac56b3 feat: OIDC/LDAP auth, audit log, maintenance windows, migrations
- Add OIDC (OpenID Connect) authentication with discovery URL support,
  group-based role mapping, and token introspection
- Add LDAP authentication with bind credentials, group-based role
  mapping, and configurable attribute names
- Add audit log (model, routes, templates) tracking settings changes,
  plugin enable/disable, login events
- Add migrations 0009 (widget variants), 0010 (maintenance windows),
  0011 (audit log)
- Add optional dependency groups to pyproject.toml: [ldap], [snmp]
- Add Settings → Auth tab with OIDC and LDAP configuration forms

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 08:15:15 -04:00
bvandeusenandClaude Sonnet 4.6 484da1f263 feat: show update available when catalog version differs from installed
Catalog partial now compares catalog version vs installed plugin.yaml version.
Gold border + "Update available — installed vX.Y.Z" badge when newer.
Update button uses btn-warn styling. Route passes installed_versions dict.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 18:42:50 -04:00
bvandeusenandClaude Sonnet 4.6 3f437141fb chore: update plugin catalog URL to git.fabledsword.com
Default plugins.index_url and all documentation URLs now point to
https://git.fabledsword.com/bvandeusen/FabledScryer-plugins.
Anchor /plugins/ in .gitignore so it only matches the root directory
(not docs/plugins/).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 18:36:09 -04:00
bvandeusenandClaude Sonnet 4.6 fa318073f1 chore: move plugins/ to separate repo, gitignore the directory
plugins/ is now tracked at bvandeusen/fabledscryer-plugins.
Removed tracked traefik files from this repo's index (files remain on disk).
Added plugins/ to .gitignore so the directory is ignored going forward.

PLUGIN_DIR in config.yaml still points to plugins/ for local dev and Docker.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 18:33:22 -04:00
bvandeusenandClaude Sonnet 4.6 230b542015 feat: rename to FabledScryer, multi-dashboard system, plugin management, branding
- Rename package fablednetmon → fabledscryer throughout
- Multi-dashboard: ownership, per-user defaults, HTMX edit (add/remove/reorder)
- Read-only share tokens scoped to individual dashboards
- Dashboard edit is HTMX-driven (no page reloads)
- Plugin management system: remote catalog, download/install, hot-reload, in-app restart
- plugin_index.py: fetch/cache remote index.yaml; default URL → bvandeusen/fabledscryer-plugins
- plugin_manager.py: download_and_install_plugin, hot_reload_plugin, restart_app
  - ZIP extraction handles GitHub archive formats (name-v1.0.0/, name-main/)
- Settings split into tabbed sections: General, Notifications, Ansible, Plugins
- Plugins tab: catalog browser (HTMX), install/activate/update/restart actions
- UI/branding: dark palette (#07071a), crystal ball SVG logo, animated star field,
  Libertinus Serif applied to headings, nav, labels, and section titles
- Widget registry (core/widgets.py) for dashboard plugin integration
- UPS widget.html (dashboard card) and settings/_tabs.html include
- Migrations 0005–0008: dashboards, is_default, ownership, share tokens
- docs/plugins/: writing-a-plugin.md updated with publishing guide,
  index.yaml.example template for fabledscryer-plugins repo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 18:27:56 -04:00
bvandeusenandClaude Sonnet 4.6 165a202ba4 feat: UI redesign (CSS system, DNS widget, Traefik dashboard widget)
- Replace base.html style block with full CSS design system using custom properties (dark theme, cards, tables, badges, dots, widgets)
- Add DNS blueprint (fablednetmon/dns/) with /dns/ and /dns/rows routes + templates
- Add Traefik /widget route and widget.html fragment for dashboard
- Update dashboard: DNS + Traefik widgets, traefik_enabled config detection
- Update all templates to use new CSS classes (page-title, section-title, card-flush, table, badge-*, dot-*, btn-*)
- Register dns_bp in app.py

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 23:37:46 -04:00
bvandeusen d29c5b3eab fix: suppress debconf frontend warnings during apt-get install 2026-03-18 23:25:44 -04:00
bvandeusen a3a05070e7 fix: upgrade pip, run as non-root user, remove stale FABLEDNETMON_CONFIG env 2026-03-18 23:23:52 -04:00
bvandeusen 7a7ed2185a feat: live ping pill widget (dashboard + /ping/ page with threshold settings) 2026-03-18 23:18:26 -04:00
bvandeusen 791af2d58f feat: ping/DNS status and latency in hosts list and dashboard summary 2026-03-18 23:09:49 -04:00
bvandeusen c26552b670 fix: install iputils-ping in Docker image for ICMP ping support 2026-03-18 23:03:58 -04:00
bvandeusen d8eacffd48 fix: env.py reads FABLEDNETMON_DATABASE_URL and honors URL set by migration_runner 2026-03-18 22:40:05 -04:00
bvandeusen f9ea87187b test: update test_config.py for load_bootstrap API 2026-03-18 22:31:17 -04:00
bvandeusenandClaude Sonnet 4.6 242398dc52 chore: remove config.yaml mount from docker-compose; update config example
- Replace individual volume mounts (playbook_cache, plugins) with single app_data:/data mount
- Change FABLEDNETMON_DATABASE__URL to FABLEDNETMON_DATABASE_URL (underscore to hyphen)
- Simplify config.example.yaml to focus on required database URL setting
- Document that other settings are now managed via the Settings UI

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 20:36:26 -04:00
bvandeusenandClaude Sonnet 4.6 dfb433e779 feat: settings UI (admin-only, live-updates app.config)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 20:35:39 -04:00
bvandeusenandClaude Sonnet 4.6 c5dff7ec8c feat: two-phase migrations, DB settings loading in create_app
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 20:33:36 -04:00
bvandeusen 03bbd8d0fa feat: strip config.py to bootstrap only (db_url + auto-gen secret_key) 2026-03-18 20:32:02 -04:00
bvandeusen 80ce703a15 feat: settings service (get/set/load helpers, load_settings_sync) 2026-03-18 20:29:52 -04:00
bvandeusenandClaude Sonnet 4.6 e6fa8baed1 feat: AppSetting model and migration 0004
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 20:22:23 -04:00
bvandeusen 38416b412a fix: dockerfile install order; add .dockerignore; update .gitignore 2026-03-18 19:57:05 -04:00
bvandeusen 4cc83c8a19 fix: use relative imports in traefik plugin to prevent double-registration; resolve PLUGIN_DIR path 2026-03-18 18:46:02 -04:00
bvandeusen 2164ea28f2 feat: traefik UI (per-router dashboard with SVG sparklines) 2026-03-18 18:43:05 -04:00
bvandeusen aacfcd420e feat: traefik scrape task (delta tracking, DB write, record_metric) 2026-03-18 18:38:54 -04:00
bvandeusen 8ea2b09d05 fix: cap percentile at last finite bucket when target falls in open +Inf bucket 2026-03-18 18:38:03 -04:00
bvandeusen c336f1f774 feat: traefik prometheus scraper (parse, compute rates and percentiles) 2026-03-17 21:37:34 -04:00
bvandeusenandClaude Sonnet 4.6 0af38016cd feat: traefik plugin migration (traefik_001_initial, depends_on core head)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 21:34:40 -04:00
bvandeusen 6fde57f63e feat: traefik plugin scaffold (plugin.yaml, model, __init__ stub) 2026-03-17 21:32:14 -04:00
bvandeusen 13f2a6f2d6 fix: preserve enabled key in merged plugin config; revert trailing slash on url_prefix 2026-03-17 21:31:11 -04:00
bvandeusen 400e0ee1b4 fix: use trailing slash in plugin blueprint url_prefix 2026-03-17 21:29:38 -04:00
bvandeusen c6b3672a49 feat: add plugin manager (load, validate, register plugins) 2026-03-17 21:28:37 -04:00
bvandeusen ae57f2f9da fix: always set version_locations explicitly in migration runner 2026-03-17 21:27:43 -04:00
bvandeusenandClaude Sonnet 4.6 415fe7eba9 feat: add migration runner and wire into create_app
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 21:12:06 -04:00
bvandeusenandClaude Sonnet 4.6 763cbda3ac feat: wire ansible blueprint, startup interrupted-run marker, git-pull task, cleanup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 20:33:14 -04:00
bvandeusenandClaude Sonnet 4.6 60e2040284 fix: ansible routes validation, SSE dedup, scoped querySelector, status_color fallback
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 20:31:17 -04:00
bvandeusenandClaude Sonnet 4.6 94e0f20f98 feat: add ansible routes and templates (browse, run, stream, detail)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 20:27:51 -04:00
bvandeusen 2fd9d331d6 feat: add ansible executor with SSE broadcast and DB flush 2026-03-17 20:23:34 -04:00
bvandeusen b7fba8ab5e fix: validate required url/path fields in get_sources 2026-03-17 20:22:52 -04:00
bvandeusen 90aaf8f80c feat: add ansible source discovery (local + git) 2026-03-17 20:20:48 -04:00
bvandeusen c18b707093 feat: add AnsibleRun model and migration 0003 2026-03-17 20:17:56 -04:00
bvandeusenandClaude Sonnet 4.6 7dbb662c38 feat: wire monitors, scheduler, alerts, and nav into app
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 20:01:31 -04:00
bvandeusen 75b0233c94 feat: alert rules and active alerts UI 2026-03-17 19:57:53 -04:00
bvandeusen 3f3f55b83f feat: host management UI (CRUD) 2026-03-17 19:57:51 -04:00
bvandeusen 1ef4983de6 feat: data retention cleanup task 2026-03-17 19:50:58 -04:00