Ansible schedule form: structured playbook-variable fields + first-item dropdown defaults #2

Merged
bvandeusen merged 126 commits from dev into main 2026-06-30 23:44:04 -04:00
48 changed files with 142 additions and 124 deletions
Showing only changes of commit af60ca446d - Show all commits
+4 -4
View File
@@ -13,8 +13,8 @@ from alembic import context
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
from fabledscryer.models.base import Base
import fabledscryer.models # noqa: F401
from steward.models.base import Base
import steward.models # noqa: F401
from plugins.docker.models import DockerContainer, DockerMetric # noqa: F401
config = context.config
@@ -26,14 +26,14 @@ target_metadata = Base.metadata
def _get_url() -> str:
import yaml
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
try:
with open(cfg_path) as f:
cfg = yaml.safe_load(f) or {}
url = cfg.get("database", {}).get("url", "")
except FileNotFoundError:
url = ""
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
return os.environ.get("STEWARD_DATABASE__URL", url)
def run_migrations_offline() -> None:
+1 -1
View File
@@ -4,7 +4,7 @@ import uuid
from datetime import datetime, timezone
from sqlalchemy import DateTime, Float, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column
from fabledscryer.models.base import Base
from steward.models.base import Base
class DockerContainer(Base):
+3 -3
View File
@@ -1,11 +1,11 @@
name: docker
version: "1.0.0"
description: "Docker container status, resource usage, restart tracking via Docker socket"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/docker"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/docker"
tags:
- containers
- docker
+3 -4
View File
@@ -1,13 +1,12 @@
# plugins/docker/routes.py
from __future__ import annotations
import json
from datetime import datetime, timezone
from quart import Blueprint, current_app, render_template, request
from sqlalchemy import Integer, cast, func, select
from fabledscryer.auth.middleware import require_role
from fabledscryer.models.users import UserRole
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
from steward.auth.middleware import require_role
from steward.models.users import UserRole
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
from .models import DockerContainer, DockerMetric
docker_bp = Blueprint("docker", __name__, template_folder="templates")
+2 -2
View File
@@ -4,8 +4,8 @@ import json
import logging
from datetime import datetime, timezone
from fabledscryer.core.scheduler import ScheduledTask
from fabledscryer.core.alerts import record_metric
from steward.core.scheduler import ScheduledTask
from steward.core.alerts import record_metric
logger = logging.getLogger(__name__)
-1
View File
@@ -106,7 +106,6 @@ async def scrape_docker(socket_path: str, include_stopped: bool) -> list[dict]:
) from exc
results = []
now = datetime.now(timezone.utc)
for container, stats in pairs:
names = container.get("Names") or []
name = names[0].lstrip("/") if names else _short_id(container.get("Id", ""))
+1 -1
View File
@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block title %}Docker — Fabled Scryer{% endblock %}
{% block title %}Docker — Steward{% endblock %}
{% block content %}
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;gap:1rem;flex-wrap:wrap;">
<h1 class="page-title" style="margin-bottom:0;">Docker</h1>
-1
View File
@@ -2,7 +2,6 @@
"""Core HTTP check logic — runs a single monitor check and returns a result dict."""
from __future__ import annotations
import asyncio
import json
import logging
import ssl
import time
+4 -4
View File
@@ -13,8 +13,8 @@ from alembic import context
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
from fabledscryer.models.base import Base
import fabledscryer.models # noqa: F401
from steward.models.base import Base
import steward.models # noqa: F401
from plugins.http.models import HttpMonitor, HttpResult # noqa: F401
config = context.config
@@ -26,14 +26,14 @@ target_metadata = Base.metadata
def _get_url() -> str:
import yaml
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
try:
with open(cfg_path) as f:
cfg = yaml.safe_load(f) or {}
url = cfg.get("database", {}).get("url", "")
except FileNotFoundError:
url = ""
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
return os.environ.get("STEWARD_DATABASE__URL", url)
def run_migrations_offline() -> None:
+1 -1
View File
@@ -4,7 +4,7 @@ import uuid
from datetime import datetime, timezone
from sqlalchemy import Boolean, DateTime, Float, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column
from fabledscryer.models.base import Base
from steward.models.base import Base
class HttpMonitor(Base):
+3 -3
View File
@@ -1,11 +1,11 @@
name: http
version: "1.0.0"
description: "Synthetic HTTP endpoint monitoring — status code, response time, content match, TLS expiry"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/http"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/http"
tags:
- monitoring
- http
+3 -4
View File
@@ -1,14 +1,13 @@
# plugins/http/routes.py
from __future__ import annotations
import json
import uuid
from datetime import datetime, timezone
from quart import Blueprint, current_app, render_template, request, redirect, url_for
from sqlalchemy import Integer, cast, func, select
from fabledscryer.auth.middleware import require_role
from fabledscryer.models.users import UserRole
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
from steward.auth.middleware import require_role
from steward.models.users import UserRole
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
from .models import HttpMonitor, HttpResult
http_bp = Blueprint("http", __name__, template_folder="templates")
+3 -3
View File
@@ -3,10 +3,10 @@ from __future__ import annotations
import asyncio
import json
import logging
from datetime import datetime, timezone, timedelta
from datetime import datetime, timezone
from fabledscryer.core.scheduler import ScheduledTask
from fabledscryer.core.alerts import record_metric
from steward.core.scheduler import ScheduledTask
from steward.core.alerts import record_metric
logger = logging.getLogger(__name__)
+1 -1
View File
@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block title %}HTTP Monitors — Fabled Scryer{% endblock %}
{% block title %}HTTP Monitors — Steward{% endblock %}
{% block content %}
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;gap:1rem;flex-wrap:wrap;">
<h1 class="page-title" style="margin-bottom:0;">HTTP Monitors</h1>
+22 -22
View File
@@ -1,6 +1,6 @@
# fabledscryer-plugins / index.yaml
# steward-plugins / index.yaml
#
# Plugin catalog for Fabled Scryer.
# Plugin catalog for Steward.
# Fetched by the app at: Settings → Plugins → Plugin Catalog
#
# After updating an entry, commit and push — changes are live within 5 minutes
@@ -16,12 +16,12 @@ plugins:
- name: http
version: "1.0.0"
description: "Synthetic HTTP endpoint monitoring — status code, response time, content match, TLS expiry"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/http"
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/http-v1.0.0/http.zip"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/http"
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/http-v1.0.0/http.zip"
checksum_sha256: ""
tags:
- monitoring
@@ -32,12 +32,12 @@ plugins:
- name: docker
version: "1.0.0"
description: "Docker container status, resource usage, and restart tracking via Docker socket"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/docker"
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/docker-v1.0.0/docker.zip"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/docker"
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/docker-v1.0.0/docker.zip"
checksum_sha256: ""
tags:
- containers
@@ -47,12 +47,12 @@ plugins:
- name: traefik
version: "1.0.0"
description: "Traefik reverse proxy metrics and access log integration"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/traefik"
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/traefik-v1.0.0/traefik.zip"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/traefik"
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/traefik-v1.0.0/traefik.zip"
checksum_sha256: ""
tags:
- proxy
@@ -62,12 +62,12 @@ plugins:
- name: unifi
version: "1.0.0"
description: "UniFi Network controller integration — WAN health, devices, clients, DPI"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/unifi"
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/unifi-v1.0.0/unifi.zip"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/unifi"
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/unifi-v1.0.0/unifi.zip"
checksum_sha256: ""
tags:
- network
@@ -77,12 +77,12 @@ plugins:
- name: ups
version: "1.0.0"
description: "UPS monitoring via NUT (Network UPS Tools) with Ansible shutdown automation"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/ups"
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/ups-v1.0.0/ups.zip"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/ups"
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/ups-v1.0.0/ups.zip"
checksum_sha256: ""
tags:
- ups
+3 -3
View File
@@ -2,11 +2,11 @@
name: snmp
version: "1.0.0"
description: "SNMP polling for network devices — switches, routers, printers, UPSes, etc."
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/snmp"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/snmp"
tags:
- snmp
- network
+2 -2
View File
@@ -3,7 +3,7 @@
Synchronous SNMP GET helper, run via executor.
Requires pysnmp-lextudio (maintained pysnmp fork):
pip install 'fabledscryer[snmp]'
pip install 'steward[snmp]'
If pysnmp is not installed, poll_device() returns an empty dict and logs a warning.
"""
@@ -40,7 +40,7 @@ def poll_device_sync(
"""
if not _pysnmp_available():
logger.warning("pysnmp not installed — SNMP polling disabled. "
"Install with: pip install 'fabledscryer[snmp]'")
"Install with: pip install 'steward[snmp]'")
return {}
from pysnmp.hlapi import (
+3 -3
View File
@@ -5,9 +5,9 @@ from datetime import datetime, timedelta, timezone
from quart import Blueprint, current_app, render_template, request
from sqlalchemy import func, select
from fabledscryer.auth.middleware import require_role
from fabledscryer.models.users import UserRole
from fabledscryer.models.metrics import PluginMetric
from steward.auth.middleware import require_role
from steward.models.users import UserRole
from steward.models.metrics import PluginMetric
snmp_bp = Blueprint("snmp", __name__, template_folder="templates")
+2 -4
View File
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING
if TYPE_CHECKING:
from quart import Quart
from fabledscryer.core.scheduler import ScheduledTask
from steward.core.scheduler import ScheduledTask
logger = logging.getLogger(__name__)
@@ -27,16 +27,14 @@ def make_poll_task(app: "Quart") -> ScheduledTask:
async def _do_poll(app: "Quart") -> None:
from datetime import datetime, timezone
from .poller import poll_device_sync
from fabledscryer.core.alerts import record_metric
from steward.core.alerts import record_metric
devices: list[dict] = app.config["PLUGINS"]["snmp"].get("devices", [])
if not devices:
return
loop = asyncio.get_event_loop()
now = datetime.now(timezone.utc)
async with app.db_sessionmaker() as session:
async with session.begin():
+1 -1
View File
@@ -1,6 +1,6 @@
{# plugins/snmp/templates/snmp/device.html #}
{% extends "base.html" %}
{% block title %}SNMP — {{ device_name }} — Fabled Scryer{% endblock %}
{% block title %}SNMP — {{ device_name }} — Steward{% endblock %}
{% block content %}
<div style="display:flex;align-items:center;gap:1rem;margin-bottom:1.5rem;flex-wrap:wrap;">
<a href="/plugins/snmp/" style="color:var(--text-muted);font-size:0.85rem;">&#8592; SNMP</a>
+1 -1
View File
@@ -1,6 +1,6 @@
{# plugins/snmp/templates/snmp/index.html #}
{% extends "base.html" %}
{% block title %}SNMP — Fabled Scryer{% endblock %}
{% block title %}SNMP — Steward{% endblock %}
{% block content %}
<div style="display:flex;align-items:center;gap:1rem;margin-bottom:1.5rem;">
<h1 class="page-title" style="margin:0;">SNMP Devices</h1>
+5 -5
View File
@@ -15,11 +15,11 @@ from sqlalchemy.engine import Connection
from sqlalchemy.ext.asyncio import async_engine_from_config
from alembic import context
# Make fabledscryer importable
# Make steward importable
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
from fabledscryer.models.base import Base
import fabledscryer.models # noqa: F401 — core models
from steward.models.base import Base
import steward.models # noqa: F401 — core models
from plugins.traefik.models import TraefikMetric # noqa: F401 — plugin model
config = context.config
@@ -31,14 +31,14 @@ target_metadata = Base.metadata
def _get_url() -> str:
import yaml
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
try:
with open(cfg_path) as f:
cfg = yaml.safe_load(f) or {}
url = cfg.get("database", {}).get("url", "")
except FileNotFoundError:
url = ""
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
return os.environ.get("STEWARD_DATABASE__URL", url)
def run_migrations_offline() -> None:
+1 -1
View File
@@ -4,7 +4,7 @@ import uuid
from datetime import datetime, timezone
from sqlalchemy import DateTime, Float, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column
from fabledscryer.models.base import Base
from steward.models.base import Base
class TraefikMetric(Base):
+3 -3
View File
@@ -2,11 +2,11 @@
name: traefik
version: "1.0.0"
description: "Traefik reverse proxy metrics and access log integration"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/traefik"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/traefik"
tags:
- proxy
- metrics
+3 -3
View File
@@ -6,9 +6,9 @@ from quart import Blueprint, current_app, render_template, request
from sqlalchemy import Integer, cast, func, select
import json
from fabledscryer.auth.middleware import require_role
from fabledscryer.models.users import UserRole
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds, subsample
from steward.auth.middleware import require_role
from steward.models.users import UserRole
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds, subsample
from .models import TraefikAccessSummary, TraefikCert, TraefikGlobalStat, TraefikMetric
traefik_bp = Blueprint("traefik", __name__, template_folder="templates")
+2 -3
View File
@@ -5,7 +5,7 @@ import time
from typing import TYPE_CHECKING
from datetime import datetime
from fabledscryer.core.scheduler import ScheduledTask
from steward.core.scheduler import ScheduledTask
if TYPE_CHECKING:
from quart import Quart
@@ -41,7 +41,6 @@ async def _do_scrape(app: "Quart") -> None:
global _prev_metrics, _prev_time
from datetime import datetime, timezone
from sqlalchemy import select
from .models import TraefikCert, TraefikGlobalStat, TraefikMetric
from .scraper import (
compute_global_stats,
@@ -49,7 +48,7 @@ async def _do_scrape(app: "Quart") -> None:
extract_certs,
fetch_metrics,
)
from fabledscryer.core.alerts import record_metric
from steward.core.alerts import record_metric
metrics_url: str = app.config["PLUGINS"]["traefik"]["metrics_url"]
+1 -1
View File
@@ -1,6 +1,6 @@
{# plugins/traefik/templates/traefik/index.html #}
{% extends "base.html" %}
{% block title %}Traefik — Fabled Scryer{% endblock %}
{% block title %}Traefik — Steward{% endblock %}
{% block content %}
<div style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:0.75rem;margin-bottom:1.5rem;">
<div style="display:flex;align-items:baseline;gap:1rem;">
+4 -4
View File
@@ -15,8 +15,8 @@ from alembic import context
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
from fabledscryer.models.base import Base
import fabledscryer.models # noqa: F401
from steward.models.base import Base
import steward.models # noqa: F401
from plugins.unifi.models import UnifiWanStat, UnifiClientSnapshot, UnifiDevice # noqa: F401
config = context.config
@@ -28,14 +28,14 @@ target_metadata = Base.metadata
def _get_url() -> str:
import yaml
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
try:
with open(cfg_path) as f:
cfg = yaml.safe_load(f) or {}
url = cfg.get("database", {}).get("url", "")
except FileNotFoundError:
url = ""
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
return os.environ.get("STEWARD_DATABASE__URL", url)
def run_migrations_offline() -> None:
+1 -1
View File
@@ -4,7 +4,7 @@ import uuid
from datetime import datetime, timezone
from sqlalchemy import Boolean, DateTime, Float, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column
from fabledscryer.models.base import Base
from steward.models.base import Base
# ── Time-series (one row per scrape) ──────────────────────────────────────────
+3 -3
View File
@@ -1,11 +1,11 @@
name: unifi
version: "1.0.0"
description: "UniFi Network controller integration — WAN health, devices, clients, DPI"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/unifi"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/unifi"
tags:
- network
- unifi
+3 -4
View File
@@ -1,13 +1,12 @@
# plugins/unifi/routes.py
from __future__ import annotations
import json
from datetime import datetime, timezone
from quart import Blueprint, current_app, render_template, request
from sqlalchemy import Integer, cast, func, select
from fabledscryer.auth.middleware import require_role
from fabledscryer.models.users import UserRole
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds, subsample
from steward.auth.middleware import require_role
from steward.models.users import UserRole
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
from .models import (
UnifiAlarm, UnifiClientSnapshot, UnifiDevice, UnifiDpiSnapshot,
UnifiEvent, UnifiFwRule, UnifiKnownClient, UnifiNetwork,
+2 -2
View File
@@ -5,7 +5,7 @@ import logging
from datetime import datetime, timezone
from typing import TYPE_CHECKING
from fabledscryer.core.scheduler import ScheduledTask
from steward.core.scheduler import ScheduledTask
if TYPE_CHECKING:
from quart import Quart
@@ -35,7 +35,7 @@ async def _do_poll(app: "Quart") -> None:
from .client import UnifiClient
from .models import UnifiClientSnapshot, UnifiDevice, UnifiWanStat
from fabledscryer.core.alerts import record_metric
from steward.core.alerts import record_metric
cfg = app.config["PLUGINS"]["unifi"]
+1 -1
View File
@@ -1,6 +1,6 @@
{# plugins/unifi/templates/unifi/index.html #}
{% extends "base.html" %}
{% block title %}UniFi — Fabled Scryer{% endblock %}
{% block title %}UniFi — Steward{% endblock %}
{% block content %}
<div style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:0.75rem;margin-bottom:1.25rem;">
<div style="display:flex;align-items:baseline;gap:1rem;">
+3 -4
View File
@@ -3,13 +3,12 @@ from __future__ import annotations
import asyncio
import uuid
from datetime import datetime, timezone
from pathlib import Path
from quart import (
Blueprint, Response, current_app, redirect, render_template,
request, session, url_for,
Blueprint, Response, current_app, render_template,
request, session,
)
from sqlalchemy import select, update
from sqlalchemy import select
from steward.ansible import executor, sources as src_module
from steward.auth.middleware import require_role
-1
View File
@@ -8,7 +8,6 @@ we trust the HTTPS connection to the discovery-documented token/userinfo endpoin
"""
from __future__ import annotations
import base64
import hashlib
import json
import logging
import os
-1
View File
@@ -1,7 +1,6 @@
# steward/core/plugin_manager.py
from __future__ import annotations
import hashlib
import importlib
import logging
import os
import sys
-2
View File
@@ -6,8 +6,6 @@ Called by the scheduler (hourly check) or triggered manually from Settings.
from __future__ import annotations
import asyncio
import logging
import smtplib
import ssl
from datetime import datetime, timedelta, timezone
from email.message import EmailMessage
+2 -1
View File
@@ -15,7 +15,8 @@ target_metadata = Base.metadata
def get_url() -> str:
import os, yaml
import os
import yaml
def _env(suffix: str) -> str | None:
return os.environ.get(f"STEWARD_{suffix}")
+1 -2
View File
@@ -1,6 +1,5 @@
# steward/settings/routes.py
from __future__ import annotations
import json
import logging
from pathlib import Path
from quart import Blueprint, current_app, render_template, request, redirect, url_for, session
@@ -9,7 +8,7 @@ from steward.auth.middleware import require_role
from steward.core.audit import log_audit
from steward.models.users import UserRole
from steward.core.settings import (
DEFAULTS, get_all_settings, set_setting,
get_all_settings, set_setting,
to_smtp_cfg, to_webhook_cfg, to_ansible_cfg, to_plugins_cfg,
to_oidc_cfg, to_ldap_cfg,
)
+2 -2
View File
@@ -144,12 +144,12 @@
<div class="form-group">
<label>Admin group DN</label>
<input type="text" name="ldap.admin_group_dn" value="{{ settings['ldap.admin_group_dn'] }}"
placeholder="cn=scryer-admins,ou=groups,dc=example,dc=com">
placeholder="cn=steward-admins,ou=groups,dc=example,dc=com">
</div>
<div class="form-group">
<label>Operator group DN</label>
<input type="text" name="ldap.operator_group_dn" value="{{ settings['ldap.operator_group_dn'] }}"
placeholder="cn=scryer-operators,ou=groups,dc=example,dc=com">
placeholder="cn=steward-operators,ou=groups,dc=example,dc=com">
</div>
</div>
+1 -1
View File
@@ -81,7 +81,7 @@
<div style="margin-bottom:2rem;max-width:720px;">
<div class="section-title" style="margin-bottom:0.75rem;">Plugin Repositories</div>
<p style="color:var(--text-muted);font-size:0.84rem;margin-bottom:0.75rem;">
Repositories are remote <code>index.yaml</code> files that Scryer checks for available
Repositories are remote <code>index.yaml</code> files that Steward checks for available
and updated plugins. Add repos from other developers to expand the plugin catalog.
</p>
{% include "settings/_plugin_repos.html" %}
-1
View File
@@ -1,6 +1,5 @@
import pytest
import pytest_asyncio
from pathlib import Path
import textwrap
from steward.app import create_app
@@ -1,3 +1,4 @@
import urllib.error
from unittest.mock import patch
from plugins.host_agent import agent as a
@@ -55,10 +56,6 @@ def test_build_payload_wraps_samples():
assert payload["samples"][0]["cpu_pct"] == 5.0
import urllib.error
from unittest.mock import MagicMock, patch
def test_post_payload_success():
from plugins.host_agent import agent as a
captured = {}
@@ -3,7 +3,9 @@ from plugins.host_agent.agent import RingBuffer
def test_ring_buffer_preserves_order():
rb = RingBuffer(maxlen=3)
rb.push(1); rb.push(2); rb.push(3)
rb.push(1)
rb.push(2)
rb.push(3)
assert list(rb.drain()) == [1, 2, 3]
assert len(rb) == 0
@@ -17,7 +19,8 @@ def test_ring_buffer_drops_oldest_when_full():
def test_ring_buffer_drain_clears_and_is_atomic():
rb = RingBuffer(maxlen=5)
rb.push("a"); rb.push("b")
rb.push("a")
rb.push("b")
out = list(rb.drain())
rb.push("c")
assert out == ["a", "b"]
@@ -2,7 +2,6 @@
import subprocess
from pathlib import Path
import pytest
from jinja2 import Environment, FileSystemLoader
from plugins.host_agent.routes import _agent_version, AGENT_SOURCE_PATH
-1
View File
@@ -1,4 +1,3 @@
import os
import textwrap
import pytest
from steward.config import load_bootstrap
-1
View File
@@ -1,4 +1,3 @@
import pytest
from steward.models.users import User, UserRole
+35
View File
@@ -0,0 +1,35 @@
"""Regression guard: shipped code must not reference old project names.
The FabledScryer -> Roundtable -> Steward renames repeatedly left stale package
imports behind in the (then separate) plugins (e.g. `from fabledscryer.models...`),
silently breaking every non-host_agent plugin. Now that plugins are folded in-tree
and version with core, this test fails loudly if either legacy name reappears in
the shipped Python / templates / plugin manifests.
"""
from __future__ import annotations
from pathlib import Path
import pytest
_ROOT = Path(__file__).resolve().parent.parent
_TREES = [_ROOT / "steward", _ROOT / "plugins"]
_EXTENSIONS = {".py", ".yaml", ".yml", ".html", ".j2"}
_FORBIDDEN = ("scryer", "roundtable") # case-insensitive; old project names
def _shipped_files():
for tree in _TREES:
for path in tree.rglob("*"):
if path.suffix in _EXTENSIONS and "__pycache__" not in path.parts:
yield path
@pytest.mark.parametrize("name", _FORBIDDEN)
def test_no_legacy_project_name(name):
offenders = [
str(p.relative_to(_ROOT))
for p in _shipped_files()
if name in p.read_text(encoding="utf-8", errors="ignore").lower()
]
assert not offenders, f"legacy name {name!r} found in shipped code: {offenders}"