Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
e0b8835
Add GET /api/modules/classes/ for external module-class lookups (#65)
thusser Aug 24, 2026
56298ad
Give session/CSRF cookies a project-specific name
thusser Aug 24, 2026
8d4b5f1
Fix CSRF cookie name in frontend JS after cookie rename
thusser Aug 24, 2026
7956307
Update pyobs-robotic-backend references to pyobs-portal
thusser Aug 25, 2026
cf1ad5d
Merge pull request #66 from pyobs/rename/robotic-backend-to-portal
thusser Aug 25, 2026
e17da5c
v2.0.0.dev13
thusser Aug 25, 2026
6f3e814
Add design doc for fleet-aware api_module_classes (issue #68)
thusser Aug 25, 2026
e7169e6
Add missing deps to docs/requirements.txt
thusser Aug 26, 2026
1d13906
Add CI: tests, ruff, pyrefly workflows (issue #70)
thusser Aug 26, 2026
0f9f82f
Add Dependabot auto-merge workflow
Aug 26, 2026
8f36f16
Make api_module_classes fleet-aggregating (issue #68)
thusser Aug 26, 2026
8cbb781
Address review: nested-hub collisions, unreachable propagation, CI fix
thusser Aug 26, 2026
c32f672
Merge pull request #72 from pyobs/feature/fleet-module-classes
thusser Aug 26, 2026
a4369ea
v2.0.0.dev14
thusser Aug 26, 2026
aaa7a34
Remove specs/design/ links from README
thusser Aug 26, 2026
89f62a5
Add UI screenshots to docs and README
thusser Aug 26, 2026
0b03cee
Require stable pyobs-auth>=2.0.0
thusser Aug 26, 2026
e6e5ad9
v2.0.0
thusser Aug 26, 2026
6e33997
Specs: reference shared-authz-keycloak design doc (#823)
thusser Aug 28, 2026
2e3dec0
Centralize authorization via Keycloak groups, drop local activation gate
thusser Aug 30, 2026
304cd76
Address review: switch off signed-cookie sessions before storing Keyc…
thusser Aug 30, 2026
dcaf2aa
Fix stale sqlite/session doc lines: db.sqlite3 now also holds session…
thusser Aug 31, 2026
b88b899
Merge pull request #76 from pyobs/feat/centralized-authorization
thusser Aug 31, 2026
61816a2
Default ENFORCE_LOCAL_ACTIVE=True in example/base config, preserving …
thusser Aug 31, 2026
1a37e7d
Wire in KeycloakSessionRefreshMiddleware, require pyobs-auth>=2.1.0
thusser Aug 31, 2026
2849925
Merge pull request #77 from pyobs/feat/keycloak-session-refresh-middl…
thusser Aug 31, 2026
53c9170
v2.1.0
thusser Aug 31, 2026
a224b1f
Fix "(no matching log lines)" when a time-range end date is set
thusser Sep 1, 2026
1c4c274
v2.1.2
thusser Sep 1, 2026
0129b78
Add "Update all" bulk action to the Packages page
thusser Sep 1, 2026
fafba81
Address review: fix concurrent-run race, resumed-job button state, wo…
thusser Sep 1, 2026
afea89b
Merge pull request #81 from pyobs/feat/update-all-packages
thusser Sep 1, 2026
4e46680
docs: add plan for log fullscreen button (#74)
thusser Sep 1, 2026
7cffa50
docs: mark update-all-packages plan implemented (PR #81)
thusser Sep 1, 2026
2bf9714
feat: add fullscreen toggle for log console (#74)
thusser Sep 1, 2026
bde3bb2
Merge remote-tracking branch 'origin/develop' into feat/log-fullscreen
thusser Sep 1, 2026
64657af
address review: aria-pressed on fullscreen toggle, update plan doc to…
thusser Sep 1, 2026
e18f056
Merge pull request #83 from pyobs/feat/log-fullscreen
thusser Sep 1, 2026
24a870e
docs: mark log-fullscreen-button plan implemented, closed (#74, PR #83)
thusser Sep 1, 2026
478f1af
Bump ruff from 0.16.4 to 0.16.5
dependabot[bot] Sep 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .github/workflows/dependabot-automerge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Dependabot auto-merge

on: pull_request

permissions:
contents: write
pull-requests: write

jobs:
dependabot:
runs-on: ubuntu-latest
if: ${{ github.event.pull_request.user.login == 'dependabot[bot]' }}
steps:
- name: Fetch Dependabot metadata
id: metadata
uses: dependabot/fetch-metadata@v2
with:
compat-lookup: true
- name: Enable auto-merge for patch and minor updates
if: ${{ steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor' }}
run: gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28 changes: 28 additions & 0 deletions .github/workflows/pyrefly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: pyrefly

on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]

jobs:
pyrefly:
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Check out repository code
uses: actions/checkout@v7

- name: Set up Python
uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
python-version: "3.13"

- name: Install packages
run: uv sync --all-extras --dev

- name: Run pyrefly
run: uv run pyrefly check
28 changes: 28 additions & 0 deletions .github/workflows/ruff.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: ruff

on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]

jobs:
ruff:
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Check out repository code
uses: actions/checkout@v7

- name: Set up Python
uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true
python-version: "3.13"

- name: Install packages
run: uv sync --all-extras --dev

- name: Run ruff
run: uv run ruff check modules/ pyobs_web_admin/
29 changes: 29 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Tests

on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]

jobs:
test:
name: Run Django test suite
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v7

- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true

- name: Install dependencies
run: uv sync --locked

- name: Run Django system checks
run: uv run python manage.py check

- name: Run tests
run: uv run python manage.py test
86 changes: 55 additions & 31 deletions README.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
sphinx-rtd-theme
django>=6.0.7
gunicorn>=26.0.0
packaging>=24.0
psutil>=6.0
pyobs-auth>=2.0.0.dev9
pyyaml>=6.0
requests>=2.32
ruamel.yaml>=0.18
whitenoise>=6.8
Binary file added docs/source/_static/screenshots/config-editor.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/_static/screenshots/dashboard.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 11 additions & 8 deletions docs/source/api_endpoints.rst
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,14 @@ Logs
- ``/api/modules/<name>/logs/``
- Query params: ``lines`` (default 300, capped at 2000), ``filter`` (substring/regex
applied server-side), ``since`` (ISO-8601 instant -- the time-range start date, so
only entries at or after it are returned), and ``before`` (ISO-8601 instant -- returns
the last ``lines`` entries at or before it, for the log pane's scroll-to-top "load
older logs" feature). ``since`` and ``before`` combine into a ``[since, before]``
window; ``before`` on its own is journald-only (the file backend returns ``[]``
unless ``since`` is also set). ``{"lines": [...]}``.
only entries at or after it are returned), ``until`` (ISO-8601 instant -- the
time-range end date, so only entries at or before it are returned), and ``before``
(ISO-8601 instant -- returns the last ``lines`` entries at or before it, for the log
pane's scroll-to-top "load older logs" feature). ``since``/``until`` form a
``[since, until]`` window; ``before`` (the page-back cursor) combines with ``until``
as a second upper bound, the earlier of the two winning. ``before`` on its own is
journald-only (the file backend returns ``[]`` unless ``since`` is also set).
``{"lines": [...]}``.
* - GET
- ``/api/modules/<name>/log-stats/``
- 24h level counts. ``{"stats": {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}}``.
Expand All @@ -118,9 +121,9 @@ Logs
- Fleet-wide merged tail, independent of the active host. Query params: ``lines``,
``filter``, ``modules`` -- a comma-separated list of ``<host>:<module>`` tokens
(``host`` is ``"localhost"`` or a ``HUB_HOSTS`` name); omit ``modules`` entirely for
every module on every configured host -- plus ``since`` and ``before`` (same
time-range start date and "load older logs" semantics as the per-module endpoint
above, forwarded unchanged to each configured host). ``{"lines": [...],
every module on every configured host -- plus ``since``, ``until`` and ``before``
(same time-range start/end date and "load older logs" semantics as the per-module
endpoint above, forwarded unchanged to each configured host). ``{"lines": [...],
"unreachable_hosts": [{"name", "error"}, ...]}``; each line is tagged ``[host]`` when
more than one host is selected.
* - GET
Expand Down
10 changes: 10 additions & 0 deletions docs/source/features/dashboard.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
Dashboard and module detail
############################

.. image:: ../_static/screenshots/dashboard.jpg
:alt: Dashboard showing six modules grouped under Stopped and Deactivated headings, with
Total/Running/Stopped/RAM/CPU summary tiles and per-row quick-action buttons.
:width: 100%

.. image:: ../_static/screenshots/config-editor.jpg
:alt: Module detail Config tab showing a syntax-highlighted YAML editor for a module's
config file.
:width: 100%

Dashboard
*********

Expand Down
21 changes: 13 additions & 8 deletions docs/source/features/logging.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,20 @@ the line you were looking at doesn't jump.

Setting a start date in the time-range filter turns it into a server-side ``since`` bound
rather than just a client-side filter, so the pane loads logs *since* that date and you can
page back through them. The initial fetch and every scroll-to-top page-back send the start
date as ``since``; the server bounds the query accordingly (``journalctl --since`` on the
journald backend, a timestamp window on the file backend).
page back through them. Setting an end date likewise becomes a server-side ``until`` bound,
so a past window is fetched exactly as ``[since, until]`` instead of the newest ``lines``
entries being filtered down client-side (which previously showed "no matching log lines"
for any range that ended before the newest activity). The initial fetch and every
scroll-to-top page-back send both dates as ``since``/``until``; the server bounds the query
accordingly (``journalctl --since/--until`` on the journald backend, a timestamp window on
the file backend).

Scrolling to the top pages back with ``before`` (the oldest currently-loaded line's own
timestamp). For the journald backend that's a ``journalctl --until`` cutoff alongside the
existing ``-n <lines>``, giving the next page of entries immediately before what's already
on screen. The file backend supports the same page-back once a start date is set (the window
is bounded by ``since``), but a plain ``tail -n`` has no seek/offset to page further back
*without* a start date -- so on a file-backed module with no start date the pane reports
"Beginning of available logs" the first time you scroll to the top, rather than silently
re-serving the same tail on every scroll.
on screen; the end date combines with the cursor as a second upper bound, the earlier of the
two winning. The file backend supports the same page-back once a start date is set (the
window is bounded by ``since``), but a plain ``tail -n`` has no seek/offset to page further
back *without* a start date -- so on a file-backed module with no start date the pane
reports "Beginning of available logs" the first time you scroll to the top, rather than
silently re-serving the same tail on every scroll.
1 change: 0 additions & 1 deletion modules/admin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
from django.contrib import admin

# Register your models here.
1 change: 1 addition & 0 deletions modules/ejabberd.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def _ctl_returncode(command: str, *args: str) -> int:

def _parse_session_line(line: str, has_jid: bool) -> dict:
parts = line.split("\t")
session: dict[str, str | int]
if has_jid:
jid, *rest = parts
session = {"jid": jid, **dict(zip(_SESSION_FIELDS, rest))}
Expand Down
1 change: 0 additions & 1 deletion modules/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
from django.db import models

# Create your models here.
1 change: 0 additions & 1 deletion modules/proxy.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import requests as _http

from django.conf import settings


Expand Down
2 changes: 1 addition & 1 deletion modules/pyobs_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,4 @@ def replace_aliases(matches: list[tuple[str, str]], anchor_filename: str, alias_
return alias_string


__all__ = ["pre_process_yaml"]
__all__ = ["pre_process_yaml"]
Loading
Loading